2.1 KiB
2.1 KiB
A01: Broken Access Control
Last updated: March 1, 2026
Findings
- Cross-account delete risk in
/account/confirm-delete. AUTH_DISABLEDmode allows header-based impersonation (x-user-id) and must be tightly controlled.
Fixes implemented
/account/confirm-deleteis now session-bound:
- Lookup uses
req.userId. - Request
emailmust match session user's email. - Mismatch returns
403.
- Insecure auth guard added:
AUTH_DISABLED=truenow requiresALLOW_INSECURE_AUTH_FOR_DEV=trueunlessNODE_ENV=test.
/admin/rolloverhardened:
- Still requires
AUTH_DISABLED=true. - Now also requires request IP to be internal/private.
Test coverage
api/tests/access-control.account-delete.test.ts
- Verifies cross-account deletion attempt is denied (
403). - Verifies victim account is not deleted.
api/tests/auth.routes.test.ts
- Verifies protected route rejects unauthenticated access.
- Verifies spoofed
x-user-idis rejected when auth is enabled. - Verifies login/session/logout behavior with CSRF handling.
- Verifies login lockout behavior.
api/tests/access-control.admin-rollover.test.ts
- Verifies unauthenticated access to
/admin/rolloveris denied whenAUTH_DISABLED=false. - Verifies authenticated access still receives
403whenAUTH_DISABLED=false. - Verifies
/admin/rolloverrejects non-internal client IP whenAUTH_DISABLED=true. - Verifies
/admin/rolloverallows internal client IP whenAUTH_DISABLED=true.
Run commands
From api/:
npm test -- tests/auth.routes.test.ts tests/access-control.account-delete.test.ts tests/access-control.admin-rollover.test.ts
Expected results
- All three test files pass.
- No access granted to protected routes without valid auth cookie/JWT.
- Spoofed
x-user-iddoes not bypass auth whenAUTH_DISABLED=false. - Cross-account delete attempt fails with
403. /admin/rolloverremains inaccessible from public/non-internal clients.
Production configuration requirements
AUTH_DISABLED=falseALLOW_INSECURE_AUTH_FOR_DEV=false- Strong
JWT_SECRETandCOOKIE_SECRET