Files

4.3 KiB

phase, slug, status, threats_open, asvs_level, created
phase slug status threats_open asvs_level created
07.4 security-token-fingerprinting-token-binding-inserted verified 0 1 2026-06-06

Phase 07.4 — Security

Per-phase security contract: threat register, accepted risks, and audit trail.


Trust Boundaries

Boundary Description Data Crossing
client → API (login/refresh) Client User-Agent and Accept-Language headers are untrusted; HMAC treats them as opaque bytes — no injection vector Header strings → HMAC-SHA256 digest (hex)
JWT payload → get_current_user fgp claim extracted from decoded (ES256 signature-verified) JWT; attacker cannot forge without ES256 private key fgp hex string (16 chars)
fgp comparison Fixed-length (16-char hex) strings compared with hmac.compare_digest Constant-time boolean
test harness → test DB xfail stubs (Plan 01) create no DB state; no trust boundary crossed None

Threat Register

Threat ID Category Component Disposition Mitigation Status
T-07.4-01 Spoofing Access token replay from different device mitigate fgp mismatch → HTTP 401 in deps/auth.py:98-101; attacker must match UA + Accept-Language from original client context closed
T-07.4-02 Information Disclosure Timing attack on fingerprint comparison mitigate hmac.compare_digest (constant-time) used at deps/auth.py:98; satisfies SEC-06 requirement closed
T-07.4-03 Spoofing Empty-string collision (CLI clients share one fingerprint) accept D-02 deliberate design decision — CLI tools with no UA headers bind to fgp("","") and are internally consistent; equivalent to pre-7.4 security level for those clients closed
T-07.4-04 Tampering fgp HTTPException swallowed by broad except mitigate fgp validation block placed outside try/except in deps/auth.py:88-104 (pure computation, no I/O); HTTP 401 always propagates closed
T-07.4-SC Tampering Supply-chain via npm/pip/cargo installs accept No new third-party packages installed in either plan; only stdlib hmac and hashlib used closed

Status: open · closed Disposition: mitigate (implementation required) · accept (documented risk) · transfer (third-party)


Accepted Risks Log

Risk ID Threat Ref Rationale Accepted By Date
AR-07.4-01 T-07.4-03 CLI clients (no User-Agent or Accept-Language) all share fgp("") — they are internally consistent but one CLI session token cannot distinguish another CLI session. Design decision D-02 documents this as acceptable: CLI use is already authenticated via the same token family; the fingerprint adds value for browser clients where header variance is meaningful. project owner (gsd workflow) 2026-06-06
AR-07.4-02 T-07.4-SC Plans 01 and 02 introduce zero new dependencies; stdlib hmac/hashlib only. Supply-chain risk is identical to baseline. project owner (gsd workflow) 2026-06-06

Implementation Evidence

File Evidence
backend/services/auth.py:87-88 _compute_fgp(user_agent, accept_lang) — HMAC-SHA256 producing 16-char hex digest
backend/services/auth.py:115 "fgp": _compute_fgp(user_agent, accept_lang) embedded in access token payload
backend/api/auth.py:293, 372 Login and refresh both pass user_agent=request.headers.get("User-Agent", "")
backend/deps/auth.py:88-104 fgp validation block — outside try/except, hmac.compare_digest comparison, detail="Token fingerprint mismatch" on mismatch
backend/tests/test_auth_fgp.py 4 FGP tests (FGP-01..04) — all passing (promoted from xfail stubs in Plan 01)

Security Audit Trail

Audit Date Threats Total Closed Open Run By
2026-06-06 5 5 0 gsd-secure-phase (automated — short-circuit: register_authored_at_plan_time=true, threats_open=0)

Sign-Off

  • All threats have a disposition (mitigate / accept / transfer)
  • Accepted risks documented in Accepted Risks Log
  • threats_open: 0 confirmed
  • status: verified set in frontmatter

Approval: verified 2026-06-06