chore: root commit of OWSAP security testing/tightening
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

This commit is contained in:
2026-03-01 20:46:47 -06:00
parent 1645896e54
commit 079b8b9492
25 changed files with 1131 additions and 107 deletions

View File

@@ -0,0 +1,62 @@
# 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`.
2. Insecure auth guard added:
- `AUTH_DISABLED=true` now requires `ALLOW_INSECURE_AUTH_FOR_DEV=true` unless `NODE_ENV=test`.
3. `/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.
2. `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.
3. `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/`:
```bash
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`