Discovered during review of #2083.
File: packages/api/src/middleware/auth.ts:53-57
When an incoming request carries X-API-Key matching PACKRAT_API_KEY, the authPlugin injects { userId: 0, role: 'ADMIN' } into the request context.
Impact: any route protected by isAuthenticated: true (not just isAdmin) now runs with full admin posture for the API-key path, and with a forged userId: 0. Any handler that scopes its query by eq(x.userId, user.userId) will touch rows owned by user 0 (leak on reads, overwrite on writes) if such rows exist, or silently succeed as a no-op if they don't.
Fix options:
- Reject the API-key path for user-scoped routes (return 401/403 unless the route is explicitly marked service-account-safe)
- Require a real service-account userId associated with the API key; do not synthesize
- At minimum, fail closed on user-scoped handlers (detect synthesized identity and 401)
Related: #2083 (introduced by the Hono → Elysia rewrite of this middleware)
Test requirement (for the restored auth.test.ts): API-key path must not satisfy user-scoped handlers.
Discovered during review of #2083.
File:
packages/api/src/middleware/auth.ts:53-57When an incoming request carries
X-API-KeymatchingPACKRAT_API_KEY, theauthPlugininjects{ userId: 0, role: 'ADMIN' }into the request context.Impact: any route protected by
isAuthenticated: true(not justisAdmin) now runs with full admin posture for the API-key path, and with a forgeduserId: 0. Any handler that scopes its query byeq(x.userId, user.userId)will touch rows owned by user 0 (leak on reads, overwrite on writes) if such rows exist, or silently succeed as a no-op if they don't.Fix options:
Related: #2083 (introduced by the Hono → Elysia rewrite of this middleware)
Test requirement (for the restored
auth.test.ts): API-key path must not satisfy user-scoped handlers.