Security hardening: v2 assessment remediation #7

Merged
JoeBot merged 1 commits from claude/tender-murdock into main 2026-03-17 07:46:57 -04:00
Owner

Summary

  • L2: Hide nginx version via server_tokens off on both production configs
  • M1: Add security headers (X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy) to all nginx routes for consistent coverage
  • L3: Global NoCacheInterceptor sets Cache-Control: no-store on all API responses, preventing browsers/proxies from caching sensitive financial data
  • C1: Disable open self-registration by default — gated behind ALLOW_OPEN_REGISTRATION=true env var
  • H3: Add logout endpoint with correct @HttpCode(200)
  • M2: Full password reset flow — POST /auth/forgot-password, POST /auth/reset-password, PATCH /auth/change-password with hashed tokens, 15-min expiry, single-use, account enumeration prevention
  • Reduce JWT access token expiry from 24h to 1h
  • Add EmailService stub (logs to shared.email_log — swap for Resend/SendGrid when ready)
  • Add DB migration 016 for password_reset_tokens table

Test plan

  • Verify POST /api/auth/register returns 403 when ALLOW_OPEN_REGISTRATION is not set
  • Verify POST /api/auth/forgot-password returns 200 for both existing and non-existing emails
  • Verify POST /api/auth/reset-password with valid token updates password
  • Verify POST /api/auth/reset-password with expired/used token returns 400
  • Verify PATCH /api/auth/change-password requires correct current password
  • Verify POST /api/auth/logout returns 200
  • Verify API responses include Cache-Control: no-store header
  • Verify nginx responses no longer include version in Server header
  • Run migration 016 against database
  • Deploy and re-run security assessment to confirm fixes

🤖 Generated with Claude Code

## Summary - **L2**: Hide nginx version via `server_tokens off` on both production configs - **M1**: Add security headers (`X-Frame-Options`, `X-Content-Type-Options`, `Referrer-Policy`, `Permissions-Policy`) to all nginx routes for consistent coverage - **L3**: Global `NoCacheInterceptor` sets `Cache-Control: no-store` on all API responses, preventing browsers/proxies from caching sensitive financial data - **C1**: Disable open self-registration by default — gated behind `ALLOW_OPEN_REGISTRATION=true` env var - **H3**: Add logout endpoint with correct `@HttpCode(200)` - **M2**: Full password reset flow — `POST /auth/forgot-password`, `POST /auth/reset-password`, `PATCH /auth/change-password` with hashed tokens, 15-min expiry, single-use, account enumeration prevention - Reduce JWT access token expiry from 24h to 1h - Add `EmailService` stub (logs to `shared.email_log` — swap for Resend/SendGrid when ready) - Add DB migration 016 for `password_reset_tokens` table ## Test plan - [ ] Verify `POST /api/auth/register` returns 403 when `ALLOW_OPEN_REGISTRATION` is not set - [ ] Verify `POST /api/auth/forgot-password` returns 200 for both existing and non-existing emails - [ ] Verify `POST /api/auth/reset-password` with valid token updates password - [ ] Verify `POST /api/auth/reset-password` with expired/used token returns 400 - [ ] Verify `PATCH /api/auth/change-password` requires correct current password - [ ] Verify `POST /api/auth/logout` returns 200 - [ ] Verify API responses include `Cache-Control: no-store` header - [ ] Verify nginx responses no longer include version in `Server` header - [ ] Run migration 016 against database - [ ] Deploy and re-run security assessment to confirm fixes 🤖 Generated with [Claude Code](https://claude.com/claude-code)
JoeBot added 1 commit 2026-03-17 07:43:37 -04:00
- L2: Add server_tokens off to nginx configs to hide version
- M1: Add X-Frame-Options, X-Content-Type-Options, Referrer-Policy,
  Permissions-Policy headers to all nginx routes
- L3: Add global NoCacheInterceptor (Cache-Control: no-store) on all
  API responses to prevent caching of sensitive financial data
- C1: Disable open registration by default (ALLOW_OPEN_REGISTRATION env)
- H3: Add logout endpoint with correct HTTP 200 status code
- M2: Implement full password reset flow (forgot-password, reset-password,
  change-password) with hashed tokens, 15-min expiry, single-use
- Reduce JWT access token expiry from 24h to 1h
- Add EmailService stub (logs to shared.email_log)
- Add DB migration 016 for password_reset_tokens table

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
JoeBot force-pushed claude/tender-murdock from fb20c917e1 to 19fb2c037c 2026-03-17 07:46:50 -04:00 Compare
JoeBot merged commit 8abab40778 into main 2026-03-17 07:46:57 -04:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: JoeBot/HOA_Financial_Platform#7
No description provided.