Files
SkyMoney/tests-results-for-OWASP/A01-Broken-Access-Control.md
Ricearoni1245 079b8b9492
All checks were successful
Deploy / deploy (push) Successful in 1m42s
Security Tests / security-non-db (push) Successful in 20s
Security Tests / security-db (push) Successful in 22s
chore: root commit of OWSAP security testing/tightening
2026-03-01 20:46:47 -06:00

2.1 KiB

A01: Broken Access Control

Last updated: March 1, 2026

Findings

  1. Cross-account delete risk in /account/confirm-delete.
  2. AUTH_DISABLED mode allows header-based impersonation (x-user-id) and must be tightly controlled.

Fixes implemented

  1. /account/confirm-delete is now session-bound:
  • Lookup uses req.userId.
  • Request email must match session user's email.
  • Mismatch returns 403.
  1. Insecure auth guard added:
  • AUTH_DISABLED=true now requires ALLOW_INSECURE_AUTH_FOR_DEV=true unless NODE_ENV=test.
  1. /admin/rollover hardened:
  • Still requires AUTH_DISABLED=true.
  • Now also requires request IP to be internal/private.

Test coverage

  1. api/tests/access-control.account-delete.test.ts
  • Verifies cross-account deletion attempt is denied (403).
  • Verifies victim account is not deleted.
  1. api/tests/auth.routes.test.ts
  • Verifies protected route rejects unauthenticated access.
  • Verifies spoofed x-user-id is rejected when auth is enabled.
  • Verifies login/session/logout behavior with CSRF handling.
  • Verifies login lockout behavior.
  1. api/tests/access-control.admin-rollover.test.ts
  • Verifies unauthenticated access to /admin/rollover is denied when AUTH_DISABLED=false.
  • Verifies authenticated access still receives 403 when AUTH_DISABLED=false.
  • Verifies /admin/rollover rejects non-internal client IP when AUTH_DISABLED=true.
  • Verifies /admin/rollover allows internal client IP when AUTH_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

  1. All three test files pass.
  2. No access granted to protected routes without valid auth cookie/JWT.
  3. Spoofed x-user-id does not bypass auth when AUTH_DISABLED=false.
  4. Cross-account delete attempt fails with 403.
  5. /admin/rollover remains inaccessible from public/non-internal clients.

Production configuration requirements

  1. AUTH_DISABLED=false
  2. ALLOW_INSECURE_AUTH_FOR_DEV=false
  3. Strong JWT_SECRET and COOKIE_SECRET