2.5 KiB
2.5 KiB
A02: Security Misconfiguration
Last updated: March 1, 2026
Findings addressed
- SMTP transport debug logging enabled in all environments.
- Production CORS had a fail-open branch when configured origins were empty.
- Missing explicit anti-framing headers at edge.
- Docker compose exposed Postgres/API on all host interfaces.
Fixes implemented
- SMTP transport hardening in API:
requireTLSnow respects config (SMTP_REQUIRE_TLS).- SMTP debug/logger are disabled in production (
!isProdonly).
- CORS production behavior tightened:
- Removed fail-open branch for empty configured origins.
- Production now allows only explicitly configured origins.
- Edge header hardening:
- Added
X-Frame-Options: DENY. - Added
Content-Security-Policy: frame-ancestors 'none'.
- Compose exposure reduction:
- Bound Postgres and API ports to localhost only.
Files changed
api/src/server.tsCaddyfile.prodCaddyfile.devdeploy/nginx/skymoneybudget.com.confdocker-compose.yml
Verification
Automated security regression tests
Command (A01 regression):
cd api
npm test -- auth.routes.test.ts access-control.account-delete.test.ts
Verified output (provided from host run):
- Test Files:
2 passed (2) - Tests:
6 passed (6) - Start time:
16:39:35
Command (A02 dedicated suite):
cd api
npx vitest --run -c vitest.security.config.ts
Verified output:
- Test Files:
1 passed (1) - Tests:
5 passed (5) - Suite:
tests/security-misconfiguration.test.ts
Coverage in dedicated suite:
- Production CORS allowlist enforcement (allowed origin accepted, denied origin does not receive allow headers).
- SMTP production mailer options disable debug/logger.
- Runtime CORS preflight headers validated for allowed origins (
allow-origin,allow-credentials,vary). - Edge config files contain anti-framing headers (
X-Frame-Options,frame-ancestorsCSP). docker-compose.ymlbinds Postgres/API ports to localhost only.
Expected operational checks after deploy
- Unauthenticated
GET /dashboardreturns401. - Spoofed
x-user-iddoes not bypass auth whenAUTH_DISABLED=false. /admin/rolloverremains inaccessible from public network.- Response headers include anti-framing policy.
Residual notes
- Keep production env pinned to:
AUTH_DISABLED=falseALLOW_INSECURE_AUTH_FOR_DEV=false
- Keep CORS origins explicitly configured in production:
CORS_ORIGINand/orCORS_ORIGINS.