docs(adr-0021): phase-2 security baseline (helmet, CORS, CSRF, rate-limit, error envelope) #124
Reference in New Issue
Block a user
Delete Branch "docs/adr-0021-phase-2-security-baseline"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Documents the security middleware stack shipped across the five most recent BFF PRs (#115, #117, #120, #122, #123) as a single MADR ADR. Today the rationale for each choice lives in code comments and PR descriptions; the next contributor reaching for
csurf, a cookie-only CSRF, or a hardcoded localhost CORS fallback won't have a single place to read why those are wrong here.ADR-0021 covers:
{ error: { code, message, traceId } }, single contract shared between Nest'sStructuredErrorFilterand raw Express middlewares (CSRF, rate-limit) via the exportederrorResponse()helper. Status code → code mapping documented. 500s never leak the underlying exception.CORS_ALLOWED_ORIGINSmandatory at boot, no fallback. "Works in dev, breaks in prod" is the exact trap the validator catches./auth/login+/auth/callback, 120/min general,/api/healthskipped. In-memory v1 store; Redis-backed migration is one constructor arg.crossOriginResourcePolicy: cross-origin, CSP prod-only). Each override has a code-anchored justification.Scope
This is the implementation-level security ADR. The strategic security baseline ADR — OWASP ASVS reference level, HDS / GDPR / NIS 2 framing, RSSI sign-off — remains paused per the note in CLAUDE.md. When that ADR lands it'll either confirm 0021 or supersede pieces of it; 0021 is explicit about which choices are tactical and revisitable.
Notable structural choices in the ADR
csurfvs synchronizer. For rate-limit bucket key: sessionID-then-IP vs IP-only vs Entraoid. Each rejected option has its "Bad, because …" so the reader sees why we didn't go that way.detailsfield in the envelope for field-level validation errors yet. These aren't hidden in the prose.Other doc touches
Noted for a separate PR (out of scope here)
CLAUDE.md §"Repository status" still says "The Nx workspace is not yet bootstrapped" and refs ADRs up to 0020. The whole paragraph is stale (the project is fully scaffolded, 22 ADRs in place). Worth a small dedicated docs PR.
Test plan
pnpm exec prettier --check docs/decisions/→ clean.status,date,decision-makers,tags; sections in the canonical order).security,backend.docs/decisions/README.mdupdated in the same change.