4.3 KiB
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: 0confirmedstatus: verifiedset in frontmatter
Approval: verified 2026-06-06