[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6C2DZDA3Z2GE6M3R7V4NEEK":3,"skill-same:01M6C2DZDA3Z2GE6M3R7V4NEEK":81},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":31,"publishedAt":49,"linkOnly":50,"markdownContent":51,"markdownBody":52,"frontMatter":53,"refName":57,"commitSha":58,"skillDirectory":59,"forksCount":60,"repositoryHtmlUrl":61,"repositoryHomepageUrl":62,"ownerHtmlUrl":63,"ownerBlogUrl":64,"ownerDescription":65,"updatedAt":66,"install":67,"resources":80},"01M6C2DZDA3Z2GE6M3R7V4NEEK","auth-factor-design",null,"Decision aid for authentication factor architecture — have\u002Fknow\u002Fare mapping, coercion resistance, FIDO2 PIN\u002FUV policy, and PRF hot-path anti-patterns.","jmagly\u002Faiwg","jmagly","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F1159087?v=4","01M6C10AK8N2WCSQN11FYGTJWN","Joseph Magly","01M6C10AQ8A2RMED1Y1BSVY7NF",229,"MIT","https:\u002F\u002Fgithub.com\u002Fjmagly\u002Faiwg\u002Fblob\u002Fmain\u002Fagentic\u002Fcode\u002Fframeworks\u002Fsecurity-engineering\u002Fskills\u002Fauth-factor-design\u002FSKILL.md",[18,23,26],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000015","视觉设计","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",{"categoryNo":27,"categoryName":28,"taxonomyType":29,"taxonomyTypeDesc":30},"01JBSEEDCAT000000000000032","设计师","PROFESSION","适用职业",[32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48],"auth","factor","design","auth factor design","decision","for","path","mapping","patterns","uv","anti-patterns","pin","FIDO2","coercion","authentication","architecture","policy","2026-11-10 10:12:30",false,"---\nnamespace: aiwg\nname: auth-factor-design\nplatforms: [all]\ndescription: Decision aid for authentication factor architecture — have\u002Fknow\u002Fare mapping, coercion resistance, FIDO2 PIN\u002FUV policy, and PRF hot-path anti-patterns.\n\n---\n\n# auth-factor-design\n\nDecision aid for authentication factor architecture. Use when designing or reviewing any system whose unlock, login, or operation gating depends on more than one factor — and especially when biometrics, hardware tokens, or \"something you know\" enter the design.\n\nThe skill forces three explicit exercises: a **factor inventory**, a **coercion-resistance matrix**, and a **lockout\u002Frecovery policy**. Without all three, the design isn't complete.\n\n## Triggers\n\n- \"factor design\" \u002F \"MFA\" \u002F \"multi-factor\"\n- \"FIDO2 PIN\" \u002F \"WebAuthn PIN\"\n- \"biometric policy\" \u002F \"uv=true\"\n- \"coercion resistance\" \u002F \"rubber-hose\"\n- \"PRF hot path\" \u002F \"hmac-secret\"\n- \"what you know vs what you have\"\n- \"duress code\" \u002F \"duress factor\"\n\n## When NOT to use this skill\n\n- Pure password-based authentication for low-stakes systems (use OWASP ASVS L1 guidance)\n- OAuth\u002FOIDC client design (different layer; use `sdlc-complete` security-architect for protocol selection)\n- Network-layer mutual TLS (cert authentication, not user authentication)\n\n---\n\n## Section 1: The three factor classes\n\n| Class | Examples | What \"knowing it\" means |\n|---|---|---|\n| **Have** | Hardware token, USB drive, smart card, phone with attestation | Possession demonstrates auth |\n| **Know** | Password, PIN, passphrase, recovery code, pattern, security questions | Recall demonstrates auth |\n| **Are** | Fingerprint, face, voice, gait, behavioral biometrics | Body demonstrates auth |\n\nA \"true\" multi-factor system requires factors from at least **two distinct classes**. Three of the same class is not multi-factor — two passwords is one factor twice.\n\n### Common misclassifications\n\n- **SMS code**: not a \"have\" factor on its own — SIM-swappable, network-interceptable. Treat as a weak channel-bound code, not a possession proof.\n- **TOTP from phone**: weak \"have\" if phone is uncontrolled (any app can read TOTP seed if leaked). Stronger if seed is in a hardware-backed enclave (Apple Secure Enclave, Android Strongbox).\n- **Email confirmation link**: not a factor — it's a recovery channel that demonstrates control of the email account, which itself depends on factors.\n- **\"Security question\" answers**: nominally \"know\" but socially harvestable; treat as a fallback recovery hint, not a factor.\n\n---\n\n## Section 2: Factor inventory exercise (mandatory)\n\nBefore declaring an auth design complete, fill out:\n\n| Factor | Class | Specific instance | Required for which operations? | Lost-recovery procedure |\n|---|---|---|---|---|\n| YubiKey 5 OTP slot | have | hardware HMAC-SHA1 PRF | unlock, secret derivation | revoke at HQ, reissue |\n| YubiKey Bio (FIDO2 PRF) | are+have | fingerprint + hmac-secret w\u002F uv=true | unlock, signing | revoke + reissue (≤4 weeks per fingerprint enrollment) |\n| FIDO2 PIN | know | PIN on Bio key | required when `uv=true` | reset via reset-protocol; bricks key after N failures |\n| Recovery passphrase | know | 6-word BIP39 phrase | emergency rotation only | offline backup at HQ |\n\n**Required**: at least one row from each of two classes for any operation that protects high-value assets. Document operations that bypass this rule with explicit risk acceptance.\n\n---\n\n## Section 3: Coercion-resistance matrix (mandatory)\n\nFor each factor, document whether it can be coerced and what mitigates the coercion.\n\n| Factor | Coercible? | How | Mitigation |\n|---|---|---|---|\n| Password \u002F PIN | Yes — operator under duress reveals it | Mitigation: duress code that triggers fail-closed silent lockout |\n| Hardware token | Yes — physical seizure | Mitigation: time-lock, witness requirement, second-factor at HQ |\n| Biometric | **Always coerced**. Operator's body is present; \"extracting\" the biometric is trivial under duress | Mitigation: pair with a \"know\" factor (FIDO2 PIN) so coerced biometric alone fails |\n| Geolocation | Coercible (move operator) | Mitigation: not a real factor; use as risk signal only |\n\n### Anti-pattern: only have + are (review finding H2)\n\nA system with hardware token + biometric and **no \"know\" factor** is not coercion-resistant. The attacker compels the operator to come to the device with the token in hand and the finger ready. There is nothing the operator can decline to provide.\n\nA FIDO2 PIN as the third factor — REQUIRED for PRF assertion via `uv=true` — adds:\n\n- A factor only the operator's mind contains (truly something they \"know\")\n- A lockout-after-N-tries property (FIDO2 PIN bricks the key after retries; default ~8)\n- Optional duress codes (some authenticators support a separate \"wipe key on this PIN\" entry)\n\nCost: zero hardware. Recommended for any production deployment of FIDO2\u002FWebAuthn PRF.\n\n---\n\n## Section 4: FIDO2 \u002F WebAuthn PRF design\n\n### Suggested default\n\nFor hardware-backed authenticated key derivation:\n\n- **FIDO2 hmac-secret extension** (PRF in WebAuthn-2 terminology) on a token with both PIN and biometric\n- **`uv: required`** in the assertion — forces user verification\n- **PIN required** — forces \"know\" alongside \"have+are\"\n- **Per-RP credential isolation** — different RP IDs derive different PRF outputs\n\n### Tooling\n\n| Use case | Suggested tool | Vetted alternatives |\n|---|---|---|\n| Production C\u002FC++ | **libfido2** (Yubico's reference C lib) | `python-fido2` only behind a sandbox; PyHanko\u002Fcose for high-level signing |\n| FIDO2 CLI | **`fido2-token`, `fido2-assert`** (libfido2 binaries) | OpenSC for smart-card-style use |\n| Browser-side WebAuthn | Web Crypto API + `navigator.credentials.create\u002Fget` | Server libs: `webauthn4j` (JVM), `simplewebauthn` (Node), `python-fido2` (server) |\n| Testing | Yubico's `fido2-token -L`, virtual authenticators (Chrome devtools, soft-fido2) | Hardware test rigs only for pre-production validation |\n\n### Anti-pattern: Python in the PRF hot path (review finding H3)\n\n`python-fido2` in the **biometric PRF assertion path** introduces a wide attack surface for the most sensitive operation in the system:\n\n- `python-fido2`, `cryptography`, `cffi`, `pyusb` — any of these getting a typosquat or supply-chain compromise = PRF interception\n- The C path through `libfido2` is ~50KB statically linkable, audited, fewer transitive deps\n\n**Remediation options:**\n\n1. **Use `libfido2` C binaries** (`fido2-token`, `fido2-assert`) directly — they support `hmac-secret`. Drop Python from the hot path entirely.\n2. **If Python is mandatory**: vendor and pin `python-fido2` + transitive deps with hash-locked wheels in your bootstrap; verify per-wheel SHA-256 against an offline manifest; reproducibly build the bootstrap.\n3. **Either way**: run the PRF call inside a sandboxed namespace (bubblewrap, no network, no `\u002Fproc`, read-only mounts).\n\n### RP ID guidance\n\n`rp.id` in WebAuthn \u002F FIDO2 is canonically a domain name. Some authenticators behave oddly with non-domain RP IDs (e.g., \"agent-box\"). For non-web contexts:\n\n- Prefer a domain you control even if not actually web-served (`agent-box.example.com`)\n- Test with multiple authenticator firmware versions before locking RP ID\n- Document if you proceed with non-domain (review L1 finding)\n\n---\n\n## Section 5: Lockout \u002F retry policy\n\n| Factor | Failure response |\n|---|---|\n| FIDO2 PIN | Hard lockout after N failures (default ~8); brick key on M (default 3 lockout cycles); requires reset protocol with PIN+attestation |\n| Biometric on hardware token | Fall back to PIN (if PIN set); on N failures of bio, force PIN; never \"skip bio\" |\n| Application password | Rate-limit + account lock with side-channel notification; CAPTCHA after 3 failures (anti-bot, not anti-human) |\n| Recovery code (single-use) | Mark used immediately; rotate active set; alert on use |\n\n### Required exercise: document the exact behavior\n\nFor each authenticator in your system, document:\n\n```\nFactor: FIDO2 PIN on Bio key\nWrong-PIN behavior:\n  After 1: warning + 1-second delay\n  After 3: 5-second delay\n  After 5: 30-second delay\n  After 8: full lockout, requires reset\n  Lockout cycles before key brick: 3 (default)\nReset procedure:\n  fido2-token -R (factory reset, wipes credentials)\n  Re-enroll fingerprint, re-set PIN\n  Re-register with all RPs (operationally expensive — design for this)\n```\n\nIf your design doesn't have this written down, it's incomplete.\n\n---\n\n## Section 6: Duress \u002F coercion countermeasures\n\nWhen the threat model includes coercion (high-value targets, journalists, security operators in hostile environments), build in:\n\n| Countermeasure | How |\n|---|---|\n| **Duress PIN** | Separate PIN that triggers visible-success but secret wipe. Hardware support varies; some FIDO2 firmware supports it, most don't. Document if your hardware does. |\n| **Time-lock** | Operations require N-minute delay; operator can secretly trigger a longer delay during which silent alarm fires |\n| **Witness requirement** | High-value operations require a second operator present (cryptographically verified — e.g., second YubiKey assertion) |\n| **Geographic \u002F device fence** | Operations only succeed from authorized locations or hardware; revocable centrally |\n| **Silent canary \u002F heartbeat** | Operator periodically demonstrates non-coercion; missed heartbeat triggers alert (review M7: heartbeat is killable by root, mitigate via signed live image) |\n\n**Important**: every coercion countermeasure has operational cost. A duress PIN that the operator forgets locks them out as effectively as the attacker does. Test the failure modes.\n\n---\n\n## Section 7: Worked examples\n\n### Review finding H2 — \"what you have + what you are\" only\n\nOriginal design: 2-of-2 with one biometric (YubiKey 5 + YubiKey Bio with fingerprint).\n\nWhat this skill flags:\n\n- Section 3 anti-pattern: no \"know\" factor → coercion gives the attacker everything\n- Section 6: no duress countermeasure documented\n\nRemediation:\n\n- Set FIDO2 PIN on Bio key; require `uv=true` in PRF assertion\n- Document PIN lockout policy\n- Optionally add duress procedure (geographic alert, second-operator witness)\n\n### Review finding H3 — `python-fido2` in PRF hot path\n\nOriginal design: Python program calls `python-fido2` to do the biometric PRF assertion.\n\nWhat this skill flags:\n\n- Section 4 anti-pattern: Python deps in hot path → wide attack surface\n\nRemediation:\n\n- Replace with `libfido2` C tools (`fido2-token`, `fido2-assert -h hmac-secret`)\n- If Python is mandatory: vendor + hash-lock all transitive deps; sandbox the call\n\n### Review finding M4 — biometric retry behavior unclear\n\nOriginal design: `uv: REQUIRED` documented, but lockout\u002Ffallback behavior not specified.\n\nWhat this skill flags:\n\n- Section 5 mandatory exercise: exact lockout behavior must be documented\n\nRemediation:\n\n- Run `fido2-token -L` against a test key, document observed behavior under N failures\n- Verify Bio key was not factory-defaulted to \"no PIN\" (if so, set one)\n- Add behavior to `factor-design-rationale.md` per-factor\n\n---\n\n## Section 8: Output format\n\nWhen this skill is invoked as part of a review, produce a `factor-design-rationale.md` (template in `templates\u002Ffactor-design-rationale.md`) with:\n\n- Factor inventory table (Section 2)\n- Coercion-resistance matrix (Section 3)\n- Lockout\u002Fretry policy per factor (Section 5)\n- Hardware\u002Ffirmware constraints (FIDO2 version, PRF support, UV behavior)\n\nIf issues are found, produce findings in the standard format:\n\n```markdown\n### Finding: \u003CSHORT-NAME>\n\n**Severity**: BLOCK | HIGH | MEDIUM | LOW\n**Section**: auth-factor-design \u003Csection reference>\n**Issue**: \u003Cone paragraph>\n**Remediation**: \u003Cconcrete fix>\n**References**: \u003CNIST SP 800-63B, FIDO2 spec, etc.>\n```\n\n---\n\n## Related\n\n- **Companion skill**: `physical-threat-modeling` (Tier 2) — coercion is in its threat library\n- **Companion skill**: `degraded-mode-design` (Tier 2) — what happens when factors fail\n- **Companion skill**: `chain-of-trust-design` — the factors only matter if the verifier is trusted\n- **Template**: `factor-design-rationale.md`\n\n## Standards referenced\n\n- NIST SP 800-63B — Digital Identity Guidelines: Authentication\n- FIDO2 \u002F CTAP2 specification\n- WebAuthn Level 2 \u002F Level 3 specifications\n- OWASP ASVS 4.0 §2 (Authentication)\n- libfido2 documentation\n","# auth-factor-design\n\nDecision aid for authentication factor architecture. Use when designing or reviewing any system whose unlock, login, or operation gating depends on more than one factor — and especially when biometrics, hardware tokens, or \"something you know\" enter the design.\n\nThe skill forces three explicit exercises: a **factor inventory**, a **coercion-resistance matrix**, and a **lockout\u002Frecovery policy**. Without all three, the design isn't complete.\n\n## Triggers\n\n- \"factor design\" \u002F \"MFA\" \u002F \"multi-factor\"\n- \"FIDO2 PIN\" \u002F \"WebAuthn PIN\"\n- \"biometric policy\" \u002F \"uv=true\"\n- \"coercion resistance\" \u002F \"rubber-hose\"\n- \"PRF hot path\" \u002F \"hmac-secret\"\n- \"what you know vs what you have\"\n- \"duress code\" \u002F \"duress factor\"\n\n## When NOT to use this skill\n\n- Pure password-based authentication for low-stakes systems (use OWASP ASVS L1 guidance)\n- OAuth\u002FOIDC client design (different layer; use `sdlc-complete` security-architect for protocol selection)\n- Network-layer mutual TLS (cert authentication, not user authentication)\n\n---\n\n## Section 1: The three factor classes\n\n| Class | Examples | What \"knowing it\" means |\n|---|---|---|\n| **Have** | Hardware token, USB drive, smart card, phone with attestation | Possession demonstrates auth |\n| **Know** | Password, PIN, passphrase, recovery code, pattern, security questions | Recall demonstrates auth |\n| **Are** | Fingerprint, face, voice, gait, behavioral biometrics | Body demonstrates auth |\n\nA \"true\" multi-factor system requires factors from at least **two distinct classes**. Three of the same class is not multi-factor — two passwords is one factor twice.\n\n### Common misclassifications\n\n- **SMS code**: not a \"have\" factor on its own — SIM-swappable, network-interceptable. Treat as a weak channel-bound code, not a possession proof.\n- **TOTP from phone**: weak \"have\" if phone is uncontrolled (any app can read TOTP seed if leaked). Stronger if seed is in a hardware-backed enclave (Apple Secure Enclave, Android Strongbox).\n- **Email confirmation link**: not a factor — it's a recovery channel that demonstrates control of the email account, which itself depends on factors.\n- **\"Security question\" answers**: nominally \"know\" but socially harvestable; treat as a fallback recovery hint, not a factor.\n\n---\n\n## Section 2: Factor inventory exercise (mandatory)\n\nBefore declaring an auth design complete, fill out:\n\n| Factor | Class | Specific instance | Required for which operations? | Lost-recovery procedure |\n|---|---|---|---|---|\n| YubiKey 5 OTP slot | have | hardware HMAC-SHA1 PRF | unlock, secret derivation | revoke at HQ, reissue |\n| YubiKey Bio (FIDO2 PRF) | are+have | fingerprint + hmac-secret w\u002F uv=true | unlock, signing | revoke + reissue (≤4 weeks per fingerprint enrollment) |\n| FIDO2 PIN | know | PIN on Bio key | required when `uv=true` | reset via reset-protocol; bricks key after N failures |\n| Recovery passphrase | know | 6-word BIP39 phrase | emergency rotation only | offline backup at HQ |\n\n**Required**: at least one row from each of two classes for any operation that protects high-value assets. Document operations that bypass this rule with explicit risk acceptance.\n\n---\n\n## Section 3: Coercion-resistance matrix (mandatory)\n\nFor each factor, document whether it can be coerced and what mitigates the coercion.\n\n| Factor | Coercible? | How | Mitigation |\n|---|---|---|---|\n| Password \u002F PIN | Yes — operator under duress reveals it | Mitigation: duress code that triggers fail-closed silent lockout |\n| Hardware token | Yes — physical seizure | Mitigation: time-lock, witness requirement, second-factor at HQ |\n| Biometric | **Always coerced**. Operator's body is present; \"extracting\" the biometric is trivial under duress | Mitigation: pair with a \"know\" factor (FIDO2 PIN) so coerced biometric alone fails |\n| Geolocation | Coercible (move operator) | Mitigation: not a real factor; use as risk signal only |\n\n### Anti-pattern: only have + are (review finding H2)\n\nA system with hardware token + biometric and **no \"know\" factor** is not coercion-resistant. The attacker compels the operator to come to the device with the token in hand and the finger ready. There is nothing the operator can decline to provide.\n\nA FIDO2 PIN as the third factor — REQUIRED for PRF assertion via `uv=true` — adds:\n\n- A factor only the operator's mind contains (truly something they \"know\")\n- A lockout-after-N-tries property (FIDO2 PIN bricks the key after retries; default ~8)\n- Optional duress codes (some authenticators support a separate \"wipe key on this PIN\" entry)\n\nCost: zero hardware. Recommended for any production deployment of FIDO2\u002FWebAuthn PRF.\n\n---\n\n## Section 4: FIDO2 \u002F WebAuthn PRF design\n\n### Suggested default\n\nFor hardware-backed authenticated key derivation:\n\n- **FIDO2 hmac-secret extension** (PRF in WebAuthn-2 terminology) on a token with both PIN and biometric\n- **`uv: required`** in the assertion — forces user verification\n- **PIN required** — forces \"know\" alongside \"have+are\"\n- **Per-RP credential isolation** — different RP IDs derive different PRF outputs\n\n### Tooling\n\n| Use case | Suggested tool | Vetted alternatives |\n|---|---|---|\n| Production C\u002FC++ | **libfido2** (Yubico's reference C lib) | `python-fido2` only behind a sandbox; PyHanko\u002Fcose for high-level signing |\n| FIDO2 CLI | **`fido2-token`, `fido2-assert`** (libfido2 binaries) | OpenSC for smart-card-style use |\n| Browser-side WebAuthn | Web Crypto API + `navigator.credentials.create\u002Fget` | Server libs: `webauthn4j` (JVM), `simplewebauthn` (Node), `python-fido2` (server) |\n| Testing | Yubico's `fido2-token -L`, virtual authenticators (Chrome devtools, soft-fido2) | Hardware test rigs only for pre-production validation |\n\n### Anti-pattern: Python in the PRF hot path (review finding H3)\n\n`python-fido2` in the **biometric PRF assertion path** introduces a wide attack surface for the most sensitive operation in the system:\n\n- `python-fido2`, `cryptography`, `cffi`, `pyusb` — any of these getting a typosquat or supply-chain compromise = PRF interception\n- The C path through `libfido2` is ~50KB statically linkable, audited, fewer transitive deps\n\n**Remediation options:**\n\n1. **Use `libfido2` C binaries** (`fido2-token`, `fido2-assert`) directly — they support `hmac-secret`. Drop Python from the hot path entirely.\n2. **If Python is mandatory**: vendor and pin `python-fido2` + transitive deps with hash-locked wheels in your bootstrap; verify per-wheel SHA-256 against an offline manifest; reproducibly build the bootstrap.\n3. **Either way**: run the PRF call inside a sandboxed namespace (bubblewrap, no network, no `\u002Fproc`, read-only mounts).\n\n### RP ID guidance\n\n`rp.id` in WebAuthn \u002F FIDO2 is canonically a domain name. Some authenticators behave oddly with non-domain RP IDs (e.g., \"agent-box\"). For non-web contexts:\n\n- Prefer a domain you control even if not actually web-served (`agent-box.example.com`)\n- Test with multiple authenticator firmware versions before locking RP ID\n- Document if you proceed with non-domain (review L1 finding)\n\n---\n\n## Section 5: Lockout \u002F retry policy\n\n| Factor | Failure response |\n|---|---|\n| FIDO2 PIN | Hard lockout after N failures (default ~8); brick key on M (default 3 lockout cycles); requires reset protocol with PIN+attestation |\n| Biometric on hardware token | Fall back to PIN (if PIN set); on N failures of bio, force PIN; never \"skip bio\" |\n| Application password | Rate-limit + account lock with side-channel notification; CAPTCHA after 3 failures (anti-bot, not anti-human) |\n| Recovery code (single-use) | Mark used immediately; rotate active set; alert on use |\n\n### Required exercise: document the exact behavior\n\nFor each authenticator in your system, document:\n\n```\nFactor: FIDO2 PIN on Bio key\nWrong-PIN behavior:\n  After 1: warning + 1-second delay\n  After 3: 5-second delay\n  After 5: 30-second delay\n  After 8: full lockout, requires reset\n  Lockout cycles before key brick: 3 (default)\nReset procedure:\n  fido2-token -R (factory reset, wipes credentials)\n  Re-enroll fingerprint, re-set PIN\n  Re-register with all RPs (operationally expensive — design for this)\n```\n\nIf your design doesn't have this written down, it's incomplete.\n\n---\n\n## Section 6: Duress \u002F coercion countermeasures\n\nWhen the threat model includes coercion (high-value targets, journalists, security operators in hostile environments), build in:\n\n| Countermeasure | How |\n|---|---|\n| **Duress PIN** | Separate PIN that triggers visible-success but secret wipe. Hardware support varies; some FIDO2 firmware supports it, most don't. Document if your hardware does. |\n| **Time-lock** | Operations require N-minute delay; operator can secretly trigger a longer delay during which silent alarm fires |\n| **Witness requirement** | High-value operations require a second operator present (cryptographically verified — e.g., second YubiKey assertion) |\n| **Geographic \u002F device fence** | Operations only succeed from authorized locations or hardware; revocable centrally |\n| **Silent canary \u002F heartbeat** | Operator periodically demonstrates non-coercion; missed heartbeat triggers alert (review M7: heartbeat is killable by root, mitigate via signed live image) |\n\n**Important**: every coercion countermeasure has operational cost. A duress PIN that the operator forgets locks them out as effectively as the attacker does. Test the failure modes.\n\n---\n\n## Section 7: Worked examples\n\n### Review finding H2 — \"what you have + what you are\" only\n\nOriginal design: 2-of-2 with one biometric (YubiKey 5 + YubiKey Bio with fingerprint).\n\nWhat this skill flags:\n\n- Section 3 anti-pattern: no \"know\" factor → coercion gives the attacker everything\n- Section 6: no duress countermeasure documented\n\nRemediation:\n\n- Set FIDO2 PIN on Bio key; require `uv=true` in PRF assertion\n- Document PIN lockout policy\n- Optionally add duress procedure (geographic alert, second-operator witness)\n\n### Review finding H3 — `python-fido2` in PRF hot path\n\nOriginal design: Python program calls `python-fido2` to do the biometric PRF assertion.\n\nWhat this skill flags:\n\n- Section 4 anti-pattern: Python deps in hot path → wide attack surface\n\nRemediation:\n\n- Replace with `libfido2` C tools (`fido2-token`, `fido2-assert -h hmac-secret`)\n- If Python is mandatory: vendor + hash-lock all transitive deps; sandbox the call\n\n### Review finding M4 — biometric retry behavior unclear\n\nOriginal design: `uv: REQUIRED` documented, but lockout\u002Ffallback behavior not specified.\n\nWhat this skill flags:\n\n- Section 5 mandatory exercise: exact lockout behavior must be documented\n\nRemediation:\n\n- Run `fido2-token -L` against a test key, document observed behavior under N failures\n- Verify Bio key was not factory-defaulted to \"no PIN\" (if so, set one)\n- Add behavior to `factor-design-rationale.md` per-factor\n\n---\n\n## Section 8: Output format\n\nWhen this skill is invoked as part of a review, produce a `factor-design-rationale.md` (template in `templates\u002Ffactor-design-rationale.md`) with:\n\n- Factor inventory table (Section 2)\n- Coercion-resistance matrix (Section 3)\n- Lockout\u002Fretry policy per factor (Section 5)\n- Hardware\u002Ffirmware constraints (FIDO2 version, PRF support, UV behavior)\n\nIf issues are found, produce findings in the standard format:\n\n```markdown\n### Finding: \u003CSHORT-NAME>\n\n**Severity**: BLOCK | HIGH | MEDIUM | LOW\n**Section**: auth-factor-design \u003Csection reference>\n**Issue**: \u003Cone paragraph>\n**Remediation**: \u003Cconcrete fix>\n**References**: \u003CNIST SP 800-63B, FIDO2 spec, etc.>\n```\n\n---\n\n## Related\n\n- **Companion skill**: `physical-threat-modeling` (Tier 2) — coercion is in its threat library\n- **Companion skill**: `degraded-mode-design` (Tier 2) — what happens when factors fail\n- **Companion skill**: `chain-of-trust-design` — the factors only matter if the verifier is trusted\n- **Template**: `factor-design-rationale.md`\n\n## Standards referenced\n\n- NIST SP 800-63B — Digital Identity Guidelines: Authentication\n- FIDO2 \u002F CTAP2 specification\n- WebAuthn Level 2 \u002F Level 3 specifications\n- OWASP ASVS 4.0 §2 (Authentication)\n- libfido2 documentation\n",{"name":5,"namespace":54,"platforms":55,"description":7},"aiwg",[56],"all","main","6754967c344ccb087a8de06972f55a41067b291b","agentic\u002Fcode\u002Fframeworks\u002Fsecurity-engineering\u002Fskills\u002Fauth-factor-design",36,"https:\u002F\u002Fgithub.com\u002Fjmagly\u002Faiwg","https:\u002F\u002Faiwg.io","https:\u002F\u002Fgithub.com\u002Fjmagly","https:\u002F\u002Fintegrolabs.io","ml\u002Fai, industrial automation, safety\u002Fsecurity, ssi\r\n\r\nmagly.net\r\nintegrolabs.io\r\naiwg.io\r\nfortemi.com\r\npagenary.com\r\nbytecask.com","2026-11-12 21:57:33",{"source":8,"skillName":5,"commands":68,"prompt":78,"zipAvailable":79},[69,72,75],{"tool":70,"command":71},"npx","npx skills add jmagly\u002Faiwg --skill auth-factor-design",{"tool":73,"command":74},"bunx","bunx skills add jmagly\u002Faiwg --skill auth-factor-design",{"tool":76,"command":77},"pnpm","pnpm dlx skills add jmagly\u002Faiwg --skill auth-factor-design","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fjmagly\u002Faiwg\u002Fblob\u002Fmain\u002Fagentic\u002Fcode\u002Fframeworks\u002Fsecurity-engineering\u002Fskills\u002Fauth-factor-design\u002FSKILL.md",true,[],[82,110,134,140,147,161],{"skillNo":83,"name":84,"nameZh":6,"description":85,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":86,"categories":87,"keywords":89,"publishedAt":49},"01M70QA0BSYJ49EES9V4RE8QH1","host-hardening","Read-only system hardening baseline and plan-first host hardening recommendations for SSH, Docker bind addresses, firewall persistence, datastores, exporters and audit retention.","https:\u002F\u002Fgithub.com\u002Fjmagly\u002Faiwg\u002Fblob\u002Fmain\u002Fagentic\u002Fcode\u002Fplugins\u002Fsecurity-engineering\u002Fskills\u002Fhost-hardening\u002FSKILL.md",[88],{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109],"host","host hardening","hardening","read","re","recommendations","remediation","plan","port","verification","Bash","access","only","retention","audit","never","firewall","bind","secrets","request",{"skillNo":111,"name":112,"nameZh":6,"description":113,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":114,"categories":115,"keywords":120,"publishedAt":49},"01M70PNT2Z4HMZPRBTAF6073NN","exposure-analysis","Read-only firewall analysis and effective host exposure reconstruction for Docker published ports, UFW bypass, stale rules, CDN scope, IPv6 asymmetry and external probe allowlists.","https:\u002F\u002Fgithub.com\u002Fjmagly\u002Faiwg\u002Fblob\u002Fmain\u002Fagentic\u002Fcode\u002Fplugins\u002Fforensics\u002Fskills\u002Fexposure-analysis\u002FSKILL.md",[116,119],{"categoryNo":117,"categoryName":118,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000011","运维与部署",{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[121,122,123,93,124,98,125,126,100,127,90,128,102,129,130,105,106,131,132,133],"exposure analysis","analysis","unknown","credentials","collection","ufw","ports","internet","local","scope","reconstruction","operator","write",{"skillNo":135,"name":84,"nameZh":6,"description":85,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":136,"categories":137,"keywords":139,"publishedAt":49},"01M70P8QATMPKA78E4FT5D2TNA","https:\u002F\u002Fgithub.com\u002Fjmagly\u002Faiwg\u002Fblob\u002Fmain\u002Fagentic\u002Fcode\u002Fframeworks\u002Fsecurity-engineering\u002Fskills\u002Fhost-hardening\u002FSKILL.md",[138],{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[92,90,91,101,93,109,96,95,104,97,98,99,100,108,102,103,94,105,106,107],{"skillNo":141,"name":112,"nameZh":6,"description":113,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":142,"categories":143,"keywords":146,"publishedAt":49},"01M70NMPVJ5H0JH131P60FW4R8","https:\u002F\u002Fgithub.com\u002Fjmagly\u002Faiwg\u002Fblob\u002Fmain\u002Fagentic\u002Fcode\u002Fframeworks\u002Fforensics-complete\u002Fskills\u002Fexposure-analysis\u002FSKILL.md",[144,145],{"categoryNo":117,"categoryName":118,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[122,121,105,124,98,125,100,123,90,128,102,129,130,93,106,127,126,131,132,133],{"skillNo":148,"name":149,"nameZh":6,"description":150,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":151,"categories":152,"keywords":154,"publishedAt":49},"01M6CB4DDR0B4NNCFK7ZK7449H","fixture-skill","Exercise rule delivery.","https:\u002F\u002Fgithub.com\u002Fjmagly\u002Faiwg\u002Fblob\u002Fmain\u002Ftest\u002Ffixtures\u002Frule-delivery\u002Fskills\u002Ffixture-skill\u002FSKILL.md",[153],{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[155,156,157,158,159,160],"fixture skill","fixture","rule","delivery","true","exercise",{"skillNo":162,"name":163,"nameZh":6,"description":164,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":165,"categories":166,"keywords":168,"publishedAt":49},"01M6CB4AVK1W76MFMPP0JP32CJ","pi-local","Pi-local duplicate-precedence fixture.","https:\u002F\u002Fgithub.com\u002Fjmagly\u002Faiwg\u002Fblob\u002Fmain\u002Ftest\u002Ffixtures\u002Fproviders\u002Fpi\u002Fproject\u002F.pi\u002Fskills\u002Fpi-local\u002FSKILL.md",[167],{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[169,170,129,171,156],"pi","pi local","duplicate"]