Security [HIGH]: API middleware default-allows /api/* — new routes inherit public access #44

Closed
opened 2026-04-16 22:05:09 +02:00 by Hartmut · 1 comment
Owner

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)

## 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)
Hartmut added the security label 2026-04-16 22:05:09 +02:00
Author
Owner

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.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Hartmut/CapaKraken#44