Severity: Important · Effort: Big-job · Dimension: Security
Location: src/middleware.ts:30
Approval gating exists only as if (!token) in middleware (line 30) — it checks authentication, never token.isApproved. isApproved is cached in the JWT (src/lib/auth.ts:28,44) but no API route consults it: every handler gates solely on if (!session?.user?.id). As a result a signed-in but unapproved user (one awaiting admin approval) can call every data route — create/read/update meal plans, recipes, pantry, stores, shopping lists, send sharing invites — with full access. The pending-approval screen is purely client-side. This is the known approval-gating gap; concrete instances are every route in src/app/api/ other than the admin routes (which separately gate on isAdmin). Severity capped at Important per REVIEW.md's single-user threat-model calibration, but it is a real authorization gap, not theoretical.
Suggested fix: Enforce approval centrally: in middleware, after the !token check, redirect to /pending-approval when token.isApproved !== true for non-exempt paths; and/or add a shared requireApprovedSession() helper used by API handlers that returns 403 with AUTH_ERRORS.FORBIDDEN when !session.user.isApproved. The redesign spec is already tracking this — capture it as a backlog item with these citations.
Scheduled: The redesign plan adds an interim server-side token.isApproved check in middleware.ts in Chunk 1 before the public beta goes live (see docs/superpowers/plans/redesign-progress.md). Related: #52 (security audit). This issue tracks the durable fix.
Surfaced by /audit-debt on 2026-05-28. Part of the pre-redesign debt backlog (docs/debt-audit-2026-05-28.md).
Severity: Important · Effort: Big-job · Dimension: Security
Location:
src/middleware.ts:30Approval gating exists only as
if (!token)in middleware (line 30) — it checks authentication, nevertoken.isApproved.isApprovedis cached in the JWT (src/lib/auth.ts:28,44) but no API route consults it: every handler gates solely onif (!session?.user?.id). As a result a signed-in but unapproved user (one awaiting admin approval) can call every data route — create/read/update meal plans, recipes, pantry, stores, shopping lists, send sharing invites — with full access. The pending-approval screen is purely client-side. This is the known approval-gating gap; concrete instances are every route in src/app/api/ other than the admin routes (which separately gate on isAdmin). Severity capped at Important per REVIEW.md's single-user threat-model calibration, but it is a real authorization gap, not theoretical.Suggested fix: Enforce approval centrally: in middleware, after the
!tokencheck, redirect to /pending-approval whentoken.isApproved !== truefor non-exempt paths; and/or add a sharedrequireApprovedSession()helper used by API handlers that returns 403 with AUTH_ERRORS.FORBIDDEN when!session.user.isApproved. The redesign spec is already tracking this — capture it as a backlog item with these citations.Surfaced by
/audit-debton 2026-05-28. Part of the pre-redesign debt backlog (docs/debt-audit-2026-05-28.md).