apps/web/src/middleware.ts lists /api/ as public prefix, exempting the entire API tree from session check. Every newly added /api/ route defaults to public unless it explicitly self-authenticates. Audit cron endpoints for fail-closed behavior (CRON_SECRET unset).
Evidence
apps/web/src/middleware.ts:6-14 — PUBLIC_PREFIXES includes '/api/'
apps/web/src/app/api/cron/public-holidays/route.ts:22-54 — gated on verifyCronSecret
apps/web/src/app/api/cron/security-audit/route.ts:110-154 — same
Impact
Default-allow pattern. A newly added /api/debug/* or /api/internal/* route is public unless a developer remembers to gate it manually.
Proposed Fix
Allowlist only: /api/auth/*, /api/trpc/*, /api/health, /api/cron/* (which self-auth via CRON_SECRET), /api/sse/*. All other /api/* require session by default. Verify verifyCronSecret fails-closed when env missing, add unit test.
Acceptance Criteria
Default-deny: new /api route requires explicit allowlist entry
Unit test for verifyCronSecret: missing CRON_SECRET → 401
## Problem
`apps/web/src/middleware.ts` lists `/api/` as public prefix, exempting the entire API tree from session check. Every newly added `/api/` route defaults to public unless it explicitly self-authenticates. Audit cron endpoints for fail-closed behavior (`CRON_SECRET` unset).
## Evidence
- `apps/web/src/middleware.ts:6-14 — PUBLIC_PREFIXES includes '/api/'`
- `apps/web/src/app/api/cron/public-holidays/route.ts:22-54 — gated on verifyCronSecret`
- `apps/web/src/app/api/cron/security-audit/route.ts:110-154 — same`
## Impact
Default-allow pattern. A newly added `/api/debug/*` or `/api/internal/*` route is public unless a developer remembers to gate it manually.
## Proposed Fix
Allowlist only: `/api/auth/*`, `/api/trpc/*`, `/api/health`, `/api/cron/*` (which self-auth via CRON_SECRET), `/api/sse/*`. All other `/api/*` require session by default. Verify `verifyCronSecret` fails-closed when env missing, add unit test.
## Acceptance Criteria
- [ ] Default-deny: new /api route requires explicit allowlist entry
- [ ] Unit test for verifyCronSecret: missing CRON_SECRET → 401
- [ ] Existing endpoints remain functional
---
Parent Epic: #1
Source: Full-Codebase Security Audit 2026-04-16 (A-13, B-24)
Resolved in commit b32160d (security: default-deny /api middleware allowlist). The web app middleware now allowlists known public /api/* routes; new routes default to auth-required.
Resolved in commit b32160d (`security: default-deny /api middleware allowlist`). The web app middleware now allowlists known public `/api/*` routes; new routes default to auth-required.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem
apps/web/src/middleware.tslists/api/as public prefix, exempting the entire API tree from session check. Every newly added/api/route defaults to public unless it explicitly self-authenticates. Audit cron endpoints for fail-closed behavior (CRON_SECRETunset).Evidence
apps/web/src/middleware.ts:6-14 — PUBLIC_PREFIXES includes '/api/'apps/web/src/app/api/cron/public-holidays/route.ts:22-54 — gated on verifyCronSecretapps/web/src/app/api/cron/security-audit/route.ts:110-154 — sameImpact
Default-allow pattern. A newly added
/api/debug/*or/api/internal/*route is public unless a developer remembers to gate it manually.Proposed Fix
Allowlist only:
/api/auth/*,/api/trpc/*,/api/health,/api/cron/*(which self-auth via CRON_SECRET),/api/sse/*. All other/api/*require session by default. VerifyverifyCronSecretfails-closed when env missing, add unit test.Acceptance Criteria
Parent Epic: #1
Source: Full-Codebase Security Audit 2026-04-16 (A-13, B-24)
Resolved in commit
b32160d(security: default-deny /api middleware allowlist). The web app middleware now allowlists known public/api/*routes; new routes default to auth-required.