KeiSeiKit-1.0/skills/auth-setup/phase-5-threats.md
Parfii-bot a4e667de10 KeiSeiKit-public — clean state
Single-commit clean baseline after security scrub of niche-tells,
project codenames, internal jargon, and contributor-email leaks.

Contents:
- 100 Rust crates (_primitives/_rust/)
- 37 agent manifests (_manifests/) + generated specs (_generated/)
- 67 user-invocable skills (skills/)
- 33 hooks (hooks/)
- Composition blocks (_blocks/)
- Documentation (docs/, README.md)
- TS adapter packages (_ts_packages/)
- Assembler (_assembler/)
- Roles (_roles/)
- Templates (_templates/)
- Forgejo CI (.forgejo/)

Author: Denis Parfionovich <info@greendragon.info>

License: see LICENSE.
2026-05-01 12:09:03 +08:00

4.1 KiB

Phase 5 — Threats & mitigations

Close the pipeline with a per-threat checklist. The user picks which mitigations to commit to; the skill emits them into the final report so they get tracked as acceptance criteria.

5a — Threat-class click (AskUserQuestion, multi-select, pre-checked)

Pre-select every item by default — opting OUT requires a click, opting IN is the cheap path (fail-closed bias).

{
  "questions": [
    {
      "question": "Confirm the threat mitigations to enforce (pre-checked; deselect only if you have a compensating control)?",
      "header": "Threats",
      "multiSelect": true,
      "options": [
        {"label": "CSRF — SameSite + token",
         "description": "SameSite=Lax default; double-submit token for cross-origin POSTs; reject on mismatch"},
        {"label": "XSS — HttpOnly + CSP",
         "description": "HttpOnly on every auth cookie; strict CSP (no inline script); sanitise every rendered string; NEVER put session or JWT in localStorage"},
        {"label": "Session fixation — rotate on login",
         "description": "New session_id issued at every privilege change (login, logout-all, password/passkey change, MFA step-up)"},
        {"label": "Account enumeration — uniform responses",
         "description": "Same timing + wording for 'user not found' and 'wrong password'; signup and reset flows respond identically regardless of address existence"},
        {"label": "Timing attacks — constant-time compare",
         "description": "Use subtle.timingSafeEqual / crypto.constant_time_compare on password hash, token, session_id lookups"},
        {"label": "Password policy — argon2id + HIBP",
         "description": "argon2id hashing (memory≥64MB, t≥3); reject passwords found in HaveIBeenPwned k-anonymity API; min length 12, no max"},
        {"label": "Brute-force — rate limit + lockout",
         "description": "Per-account exponential backoff; per-IP sliding window; CAPTCHA after N failures; unlock via email or time"},
        {"label": "Email-link security",
         "description": "One-time tokens (random 32B, SHA-256 in DB); ≤15 min TTL; single-use; bound to email address at issue time"},
        {"label": "OAuth state + nonce",
         "description": "state (CSRF) + nonce (replay) on every authorize request; reject on mismatch; see _blocks/auth-oauth2-oidc.md"},
        {"label": "Passkey recovery path",
         "description": "Backup codes OR email magic-link OR OAuth fallback; user opts out only after explicit warning"},
        {"label": "Logging without leakage",
         "description": "Never log raw password, TOTP secret, session_id, or access_token; log userID + action + result only"},
        {"label": "Dependency hygiene",
         "description": "Auth library at latest patched version; CVE scan in CI; pin via lock file"}
      ]
    }
  ]
}

Store the confirmed subset as THREATS. Any item the user deselects must have a one-line justification recorded in the final report.

5b — Emit threat-by-threat implementation hints (inline)

For each item in THREATS, print ONE implementation line. Examples:

  • CSRF → "middleware double-submit: cookie __Host-csrf + X-CSRF-Token header; subtle.timingSafeEqual on compare."
  • Timing attacks → "Rust subtle::ConstantTimeEq; Node crypto.timingSafeEqual; Python hmac.compare_digest."
  • Passkey recovery → "register 10 single-use codes at passkey creation; store argon2id hashes; mark consumed on use."

Keep each line short — full guidance lives in the upstream blocks, not in this phase.

5c — Final report assembly

After Phase 5 completes, emit the final report template from SKILL.md with all variables filled. Add at the bottom:

Deselected threats (with justification):
- <threat name>: <one-line justification> 
(or "none" if THREATS covers every default)

Verify-criterion

  • THREATS has ≥8 of the 12 defaults selected; each deselection carries a justification line.
  • Every selected threat has an implementation hint printed (5b).
  • Final report (5c) emits the full === AUTH-SETUP REPORT === block from SKILL.md.