@blamejs/exceptd-skills 0.12.23 → 0.12.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/AGENTS.md +12 -4
  2. package/CHANGELOG.md +190 -3
  3. package/README.md +14 -1
  4. package/bin/exceptd.js +584 -166
  5. package/data/_indexes/_meta.json +31 -31
  6. package/data/_indexes/activity-feed.json +45 -45
  7. package/data/_indexes/catalog-summaries.json +19 -19
  8. package/data/_indexes/chains.json +320 -0
  9. package/data/_indexes/currency.json +9 -9
  10. package/data/_indexes/frequency.json +39 -2
  11. package/data/_indexes/jurisdiction-clocks.json +2 -2
  12. package/data/_indexes/jurisdiction-map.json +3 -1
  13. package/data/_indexes/section-offsets.json +396 -396
  14. package/data/_indexes/summary-cards.json +3 -3
  15. package/data/_indexes/token-budget.json +73 -73
  16. package/data/atlas-ttps.json +491 -19
  17. package/data/attack-techniques.json +198 -84
  18. package/data/cve-catalog.json +1309 -9
  19. package/data/exploit-availability.json +300 -10
  20. package/data/framework-control-gaps.json +395 -1
  21. package/data/global-frameworks.json +44 -19
  22. package/data/playbooks/containers.json +1 -1
  23. package/data/playbooks/crypto-codebase.json +1 -1
  24. package/data/playbooks/framework.json +1 -1
  25. package/data/playbooks/hardening.json +1 -1
  26. package/data/playbooks/library-author.json +1 -1
  27. package/data/playbooks/secrets.json +25 -1
  28. package/data/rfc-references.json +93 -1
  29. package/data/zeroday-lessons.json +475 -13
  30. package/lib/auto-discovery.js +26 -2
  31. package/lib/exit-codes.js +72 -0
  32. package/lib/flag-suggest.js +130 -0
  33. package/lib/id-validation.js +95 -0
  34. package/lib/lint-skills.js +68 -1
  35. package/lib/playbook-runner.js +321 -46
  36. package/lib/prefetch.js +113 -0
  37. package/lib/refresh-external.js +190 -8
  38. package/lib/refresh-network.js +35 -8
  39. package/lib/schemas/cve-catalog.schema.json +31 -4
  40. package/lib/schemas/playbook.schema.json +51 -0
  41. package/lib/scoring.js +41 -0
  42. package/lib/upstream-check-cli.js +16 -1
  43. package/lib/upstream-check.js +9 -0
  44. package/lib/verify.js +20 -4
  45. package/manifest-snapshot.json +1 -1
  46. package/manifest-snapshot.sha256 +1 -1
  47. package/manifest.json +59 -59
  48. package/package.json +8 -2
  49. package/sbom.cdx.json +6 -6
  50. package/scripts/check-test-coverage.js +67 -0
  51. package/scripts/verify-shipped-tarball.js +9 -0
  52. package/skills/ai-attack-surface/skill.md +11 -2
  53. package/skills/ai-c2-detection/skill.md +3 -1
  54. package/skills/ai-risk-management/skill.md +3 -1
  55. package/skills/api-security/skill.md +4 -0
  56. package/skills/attack-surface-pentest/skill.md +1 -0
  57. package/skills/container-runtime-security/skill.md +3 -1
  58. package/skills/dlp-gap-analysis/skill.md +1 -1
  59. package/skills/exploit-scoring/skill.md +2 -2
  60. package/skills/incident-response-playbook/skill.md +1 -1
  61. package/skills/kernel-lpe-triage/skill.md +6 -1
  62. package/skills/mcp-agent-trust/skill.md +7 -2
  63. package/skills/mlops-security/skill.md +1 -1
  64. package/skills/rag-pipeline-security/skill.md +4 -2
  65. package/skills/sector-financial/skill.md +1 -1
  66. package/skills/skill-update-loop/skill.md +1 -1
  67. package/skills/supply-chain-integrity/skill.md +3 -1
  68. package/skills/threat-model-currency/skill.md +1 -1
  69. package/skills/webapp-security/skill.md +2 -0
  70. package/skills/zeroday-gap-learn/skill.md +2 -2
package/AGENTS.md CHANGED
@@ -28,7 +28,13 @@ Also read [CONTEXT.md](CONTEXT.md) for a complete orientation to the skill syste
28
28
 
29
29
  11. **No-MVP ban** — A half-implemented skill is worse than no skill. Every shipped skill has: complete frontmatter, all required body sections, real data deps populated, a compliance theater check, and a concrete output format. Partial skills are not merged — they are finished or removed.
30
30
 
31
- 12. **External data version pinning** — Every reference to external data (MITRE ATLAS, NIST frameworks, CISA KEV, IETF RFCs and Internet-Drafts) must pin to a specific version. When a new version is released: (a) audit for breaking changes (renamed TTPs, replaced RFCs, deprecated controls), (b) bump `last_threat_review` in all affected skills, (c) update `_meta` version fields in the relevant `data/*.json` file, (d) update `last_verified` on affected `data/rfc-references.json` entries, (e) never silently inherit version changes. Frameworks lag RFCs; RFCs lag attacker innovation — skills must track lag at every layer. Current pinned ATLAS version: v5.1.0 (November 2025). The IETF RFC / Internet-Draft catalog lives at `data/rfc-references.json`; each entry tracks status, errata count, replaces / replaced-by, and `last_verified`.
31
+ 12. **External data version pinning** — Every reference to external data (MITRE ATLAS, MITRE ATT&CK, NIST frameworks, CISA KEV, IETF RFCs and Internet-Drafts) must pin to a specific version. When a new version is released: (a) audit for breaking changes (renamed TTPs, tactic-split moves, replaced RFCs, deprecated controls), (b) bump `last_threat_review` in all affected skills, (c) update `_meta` version fields in the relevant `data/*.json` file, (d) update `last_verified` on affected `data/rfc-references.json` entries, (e) never silently inherit version changes. Frameworks lag RFCs; RFCs lag attacker innovation — skills must track lag at every layer.
32
+
33
+ **Pinned ATLAS version: v5.4.0 (February 2026), Secure AI v2 layer (May 2026). Audit cadence: monthly** (ATLAS now ships monthly per CTID; the Secure AI v2 layered set and per-technique maturity classification are tracked separately in `data/atlas-ttps.json` via the `secure_ai_v2_layer` and `maturity` fields).
34
+
35
+ **Pinned ATT&CK version: v19.0 (April 2026). Audit cadence: semi-annual** (April and October releases). v19 split Defense Evasion (TA0005) into Stealth (TA0005) and Defense Impairment (TA0112) — affected entries in `data/attack-techniques.json` carry `tactic_moved_from` for traceability. v18 introduced Detection Strategies (DSxxxx) as first-class objects; record applicable strategy IDs on entries where canonical strategies exist.
36
+
37
+ The IETF RFC / Internet-Draft catalog lives at `data/rfc-references.json`; each entry tracks status, errata count, replaces / replaced-by, and `last_verified`.
32
38
 
33
39
  13. **Skill integrity verification** — Every skill in `manifest.json` carries an Ed25519 `signature` (base64) and a `signed_at` timestamp covering its `skill.md` content. `lib/verify.js` checks each signature against the public key at `keys/public.pem` before any skill is loaded by the orchestrator. Tampered or unsigned skills are rejected. The private key at `.keys/private.pem` is gitignored and never enters the repo. Run `node lib/verify.js` (or `npm run verify`) before shipping; sign new or changed skills with `npm run bootstrap` for first-run, or `node lib/sign.js sign-all` after content changes.
34
40
 
@@ -178,8 +184,8 @@ Right: "41% of 2025 zero-days were discovered by attackers using AI-assisted rev
178
184
  Wrong: adding a new CVE to `data/cve-catalog.json` without completing all required fields.
179
185
  Right: every new entry requires all fields defined in the CVE catalog schema. Partial entries fail the schema validation in `lib/scoring.js`.
180
186
 
181
- **DR-7: Stale ATLAS version**
182
- The current pinned version is MITRE ATLAS v5.1.0 (November 2025). When ATLAS updates: audit all TTP IDs for changes, bump `last_threat_review` in affected skills, update `_meta.atlas_version` in data files. Never silently upgrade.
187
+ **DR-7: Stale ATLAS / ATT&CK version**
188
+ Current pinned ATLAS version: **v5.4.0 (February 2026)** with the **CTID Secure AI v2 layer (May 2026)**. ATLAS audit cadence is **monthly** (CTID now ships monthly). Current pinned ATT&CK version: **v19.0 (April 2026)**, semi-annual cadence (April + October). When either source updates: audit all TTP IDs for changes (including v19's Defense Evasion → Stealth / Defense Impairment split), bump `last_threat_review` in affected skills, update `_meta` version fields in `data/atlas-ttps.json` and `data/attack-techniques.json`. Never silently upgrade.
183
189
 
184
190
  **DR-8: Missing zero-day learning loop**
185
191
  Wrong: adding a new entry to `data/cve-catalog.json` without running the learning loop.
@@ -291,7 +297,8 @@ Maintainers convert approved requests into skill files. The contributor is credi
291
297
  - [ ] All new CVEs have complete `data/cve-catalog.json` entries
292
298
  - [ ] All new CVEs have `data/zeroday-lessons.json` entries
293
299
  - [ ] All skill `data_deps` resolve to existing files
294
- - [ ] All ATLAS refs are valid v5.1.0 IDs (current pinned version)
300
+ - [ ] All ATLAS refs are valid v5.4.0 IDs (current pinned version); Secure AI v2 layer flags + maturity present on AI-pipeline entries
301
+ - [ ] All ATT&CK refs are valid v19.0 IDs (current pinned version); post-split tactics (Stealth / Defense Impairment) used where applicable
295
302
  - [ ] All framework control IDs resolve in `data/framework-control-gaps.json`
296
303
  - [ ] No skill body contains placeholder language (TODO, TBD, coming soon, placeholder)
297
304
  - [ ] No skill uses CVSS as sole risk metric
@@ -340,6 +347,7 @@ Maintainers convert approved requests into skill files. The contributor is credi
340
347
  | financial security, banking, dora, psd2 sca, swift cscf, nydfs, ffiec, mas trm, apra cps 234, tiber-eu, cbest | sector-financial |
341
348
  | federal cyber, fedramp, cmmc, eo 14028, nist 800-171, cui, fisma, m-22-09 zero trust, omb m-24-04, cisa bod/ed | sector-federal-government |
342
349
  | energy security, electric grid, nerc cip, tsa pipeline, awwa, nccs-g, aescsf, der security, inverter, smart meter | sector-energy |
350
+ | telecom security, 5g core, salt typhoon, volt typhoon, gnb integrity, lawful intercept, calea, fcc cpni, gsma nesas, ss7, diameter, gtp, 3gpp ts 33.501, o-ran, n6 n9 isolation | sector-telecom |
343
351
  | api security, owasp api top 10, bola, bfla, mass assignment, api gateway, graphql, grpc, websocket, mcp transport | api-security |
344
352
  | cloud security, cspm, cwpp, cnapp, csa ccm, aws, azure, gcp, workload identity, cloud iam, multi-cloud | cloud-security |
345
353
  | container security, kubernetes, cis k8s, pod security standards, kyverno, gatekeeper, falco, tetragon, admission policy | container-runtime-security |
package/CHANGELOG.md CHANGED
@@ -1,5 +1,192 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.12.25 — 2026-05-15
4
+
5
+ **Data-refresh release: catalog freshness, Hard Rule #7 AI-discovery posture, ATLAS v5.4 + ATT&CK v19 standards bumps, Pwn2Own Berlin 2026 forward-watch, NGINX Rift, framework deltas (PCI 4.0.1 / HIPAA 2026 NPRM / EU AI Act ITS / DORA RTS).**
6
+
7
+ ### CVE catalog adds (20)
8
+
9
+ Twenty CVE entries added with paired `data/exploit-availability.json` records, all marked `_draft: true` + `_auto_imported: true` for editorial review:
10
+
11
+ - **NGINX Rift CVE-2026-42945** — heap buffer overflow in `ngx_http_rewrite_module` (18-year-old code), CVSS 9.2 v4, unauthenticated RCE, AI-discovered by depthfirst autonomous analysis platform. Disclosed 2026-05-13; patches in nginx 1.30.1 / 1.31.0 / Plus R32 P6 / R36 P4. Public PoC. Live-patch workaround: replace unnamed PCRE captures (`$1`-`$9`) with named captures in rewrite directives. KEV-watch entry queued.
12
+ - **LiteLLM CVE-2026-30623** — Anthropic MCP SDK stdio command-injection (April 2026 advisory). Patches in LiteLLM proxy + downstream consumers.
13
+ - **CVE-2026-20182 Cisco SD-WAN** — auth-bypass → admin (CISA KEV-listed 2026-05-14).
14
+ - **CVE-2024-21626 Leaky Vessels (runc)** — `/proc/self/fd` container escape. KEV-listed.
15
+ - **CVE-2024-3094 xz-utils / liblzma backdoor** — supply-chain trust-anchor compromise. KEV-listed.
16
+ - **CVE-2024-3154 CRI-O kernel-module load** on container creation.
17
+ - **CVE-2024-40635 containerd** — integer overflow → IP mask leak.
18
+ - **CVE-2023-43472 MLflow** — path-traversal arbitrary file read.
19
+ - **CVE-2020-10148 SolarWinds Orion / SUNBURST** — auth-bypass primary supply-chain compromise.
20
+ - **CVE-2023-3519 Citrix NetScaler** — unauthenticated RCE. KEV-listed.
21
+ - **CVE-2024-1709 ConnectWise ScreenConnect** — auth-bypass. KEV-listed.
22
+ - **CVE-2025-12686 Synology BeeStation** — unauth RCE (Pwn2Own Ireland 2025).
23
+ - **CVE-2025-62847 / CVE-2025-62848 / CVE-2025-62849 QNAP QTS/QuTS hero** — Pwn2Own Ireland 2025 chain (three separate entries, all patched).
24
+ - **CVE-2025-59389 QNAP Hyper Data Protector** — critical RCE (Summoning Team / Sina Kheirkhah at Pwn2Own Ireland 2025).
25
+ - **CVE-2025-11837 QNAP Malware Remover** — code-injection in a security tool (high theater-detection value: a security product is itself the attack surface).
26
+ - **MAL-2026-TANSTACK-MINI Mini Shai-Hulud** — TeamPCP-attributed worm chain (TanStack + node-ipc + Mistral AI + UiPath + Guardrails AI, May 2026).
27
+ - **MAL-2026-ANTHROPIC-MCP-STDIO** — STDIO command-injection class disclosed by Ox Security spanning 30+ MCP servers.
28
+ - **CVE-2026-GTIG-AI-2FA placeholder** — Google GTIG first documented AI-built in-the-wild zero-day exploit (May 2026), semantic-logic 2FA bypass.
29
+
30
+ ### Hard Rule #7 — AI-discovery posture
31
+
32
+ - **AI-discovery rate raised from 10% → 33%** by promoting `ai_discovered: true` on Copy Fail (CVE-2026-31431, already true), NGINX Rift, and the GTIG zero-day; tracks toward the 41% reference rate cited in AGENTS.md. Catalog entries with speculative AI attribution (Fragnesia, Dirty Frag pair) explicitly classified as `human_researcher` with `ai_discovery_notes` recording the rationale.
33
+ - **`zeroday-lessons.json` schema additions** — `ai_discovered_zeroday` (bool), `ai_discovery_source` (enum: vendor_research / bug_bounty_ai_augmented / academic_ai_fuzzing / threat_actor_ai_built / human_researcher / unknown), `ai_discovery_date` (ISO), `ai_assist_factor` (low/moderate/high/very_high). All 10 existing entries backfilled with the new fields.
34
+ - **`exploit-availability.json` `ai_assist_factor` ladder** backfilled across all entries with the same enum.
35
+ - **`cve-catalog.json` schema tightened** — `ai_discovered` is boolean-only (was `["boolean", "string"]`; RWEP scoring treated truthy strings as positive, masking malformed entries). `ai_assisted_weaponization` is now required (paired with `ai_discovered`). New optional `ai_discovery_source` / `ai_discovery_date` / `ai_discovery_notes` fields.
36
+ - **CVE-2025-53773 cross-file consistency** reconciled — `ai_assisted_weaponization: true` (cve-catalog) vs `ai_discovery_confirmed: false` + `ai_tool_enabled: true` (exploit-availability) is a real semantic distinction (development-time AI assistance vs discovery-time AI involvement vs tool-aided exploitation); both files now carry `ai_discovery_source: "unknown"` + a clarifying `ai_discovery_notes` block.
37
+ - **GTIG canonical case** (first AI-built ITW zero-day, 2026-05-11) + **NGINX Rift AI-discovery anchor** added to seven AI-class skills (ai-attack-surface, ai-risk-management, zeroday-gap-learn, exploit-scoring, ai-c2-detection, mcp-agent-trust, rag-pipeline-security). The skills now reference the 41% AI-discovery rate explicitly per Hard Rule #7 vocabulary.
38
+ - **CTID Secure AI v2 (2026-05-06)** references added to the same five AI-class skills.
39
+
40
+ ### Standards version bumps
41
+
42
+ - **ATLAS v5.1.0 → v5.4.0** + CTID Secure AI v2 layer (May 2026). `data/atlas-ttps.json` entry count 15 → 29. Existing entries gain `secure_ai_v2_layer` + `maturity` fields per CTID's classification. New AI-attack techniques: AML.T0097-T0108 plus sub-techniques.
43
+ - **MITRE ATT&CK v17 → v19.0**. `data/attack-techniques.json` entry count 79 → 91. Defense Evasion (TA0005) split into Stealth (TA0005, retained for non-impair techniques) + Defense Impairment (TA0112). `T1562.001`, `T1562.006`, `T1027` carry a `tactic_moved_from` annotation. Detection Strategies (DSxxxx — v18 first-class addition) populated on every technique cited by skills.
44
+ - **AGENTS.md Hard Rule #12 + DR-7 + Pre-Ship Checklist** split into separate ATLAS-monthly and ATT&CK-semi-annual cadence pins (cycle 7 LLL recommendation; ATLAS now ships monthly per CTID, ATT&CK ships twice yearly).
45
+ - **15 skills' `last_threat_review` dates bumped to 2026-05-15** where ATLAS / ATT&CK refs changed.
46
+
47
+ ### Framework deltas
48
+
49
+ - **PCI DSS 4.0.1** (active 2025-03-31): four control-gap entries added (Req 6.4.3 payment-page scripts, Req 11.6.1 change/tamper detection, Req 12.3.3 cipher-suite inventory, Req 12.10.7 PAN-exposure escalation).
50
+ - **HIPAA Security Rule 2026 NPRM** (HHS-OCR-0945-AA82): four entries covering proposed 164.308 / 164.310 / 164.312 / 164.314 amendments. Marked "Final rule pending Q3 2026" — citations refresh on next release.
51
+ - **EU AI Act implementing standards**: four entries for Art. 53 GPAI provider obligations, Art. 55 systemic-risk, Annex IX conformity assessment, GPAI Code of Practice (signed Feb 2026; full application 2026-08-02).
52
+ - **DORA RTS/ITS**: four entries for subcontracting RTS (EU 2025/420, active 2026-01-17), threat-led-pen-test ITS (active 2026-Q3), incident-classification thresholds RTS, and critical-third-party-provider oversight implementing acts.
53
+ - **`data/global-frameworks.json`** `EU.frameworks.DORA` and `EU.frameworks.EU_AI_ACT` refreshed with 2026 implementing-measures blocks + expanded `framework_gaps` + `ai_coverage` + `theater_risk` fields.
54
+
55
+ ### RFC + ATLAS orphans
56
+
57
+ - **7 RFC orphans added** to `data/rfc-references.json`: RFC 7644 (SCIM 2.0), RFC 8460 (SMTP-TLS-RPT), RFC 8617 (ARC), RFC 8705 (mTLS OAuth), RFC 9112 (HTTP/1.1 revised), RFC 9449 (DPoP), RFC 9622 (TAPS Architecture). Each cited by ≥1 shipped skill (Hard Rule #4 closure).
58
+ - **1 ATLAS orphan**: AML.T0001 (Victim Research / Reconnaissance) — referenced by `defensive-countermeasure-mapping` skill but not in `data/atlas-ttps.json` pre-v0.12.25.
59
+
60
+ ### Pwn2Own Berlin 2026 forward-watch
61
+
62
+ Fifteen forward-watch entries placed across nine skills' `forward_watch:` frontmatter arrays (no aggregate `data/forward-watch.json` exists; project tracks in skill frontmatter only):
63
+
64
+ - **NGINX Rift CVE-2026-42945** — KEV-listing prediction window 14 days from disclosure (2026-05-27 estimated)
65
+ - **LiteLLM** 3-bug chain (k3vg3n) + full SSRF + Code Injection (Out Of Bounds) — embargo ends 2026-08-12
66
+ - **LM Studio** 5-bug chain (STARLabs SG)
67
+ - **OpenAI Codex** CWE-150 improper neutralization (Compass Security)
68
+ - **Chroma vector DB** CWE-190 + CWE-362 chain
69
+ - **NVIDIA Megatron Bridge** ×2 (overly-permissive allowed list + path traversal)
70
+ - **NV Container Toolkit** container escape ($50K, chompie/IBM X-Force XOR)
71
+ - **Windows 11 LPE ×3** (DEVCORE Improper Access Control, Marcin Wiązowski heap overflow, Kentaro Kawane GMO double Use-After-Free)
72
+ - **RHEL race-condition LPE** (chompie/IBM X-Force XOR)
73
+ - **Claude Code MCP collision** (Viettel Cyber Security — scored as collision, indicating a public MCP-class CVE is in flight)
74
+ - **Microsoft Edge** 4-bug sandbox escape (Orange Tsai/DEVCORE) — out-of-current-playbook scope, tracked for completeness
75
+
76
+ ### Catalog scoring
77
+
78
+ - **RWEP scoring divergence on 10 new entries reconciled** with `scoreCustom()` formula. Pre-correction the stored scores diverged by 10-38 points from the formula (most extreme: NGINX Rift stored 78, formula 40 — patch + live-patch availability + zero observed exploitation walks the score down despite the AI-discovery bonus). All entries now within ±5 of formula.
79
+
80
+ ### Deferred to v0.12.26
81
+
82
+ - **`sector-telecom` skill** — drafted (370 LOC, Salt Typhoon / Volt Typhoon / 5G core / lawful-intercept abuse / signaling-protocol attacks / OEM supply chain) but the body lint surfaced 13 issues (3 missing required sections, atlas_refs and framework_gaps referencing entries not yet in catalog, placeholder language). Folding into v0.12.26 with the proper catalog scaffolding rather than rushing a half-complete skill.
83
+
84
+ Test count: 1051 pass (5 skipped). Predeploy gates: 14/14. Skills: 38/38 signed; manifest envelope signed.
85
+
86
+ ## 0.12.24 — 2026-05-15
87
+
88
+ **Patch: security defenses, exit-code centralisation, bundle correctness, air-gap honesty, cache integrity, error-message UX, test-infra hardening, doc reconciliation.**
89
+
90
+ ### Security defenses
91
+
92
+ - **`--playbook` and positional `<playbook_id>` rejected with structured error when the id does not match `/^[a-z][a-z0-9-]{0,63}$/`.** `loadPlaybook(id)` previously did `path.join(PLAYBOOK_DIR, id + '.json')` with no charset gate; an operator who passed `--playbook ../../../etc/hosts` could exfiltrate any `*.json` file on disk via `brief` / `govern` / `direct` / `look` / `run --explain` output. Validator applies at 15 CLI sites plus the library entry point.
93
+ - **`--attestation-root` refuses all-dots segments** (`.`, `..`, `...`) in addition to the prior `..` segment refusal.
94
+ - **`--session-id` validation centralised** through `lib/id-validation.js`. Six previously duplicated `/^[A-Za-z0-9._-]{1,64}$/` sites now route through `validateIdComponent(value, role)` with `role ∈ {session, playbook, filename}`.
95
+
96
+ ### Trust chain
97
+
98
+ - **`loadExpectedFingerprintFirstLine` refuses UTF-16BE-without-BOM pin files.** Heuristic: first two bytes are `00` followed by printable ASCII → reject. Operators see a `null` return instead of mojibake (in addition to the UTF-16LE/BE-with-BOM refusals from v0.12.23).
99
+ - **`KEYS_ROTATED=1` override doubled with `console.error`** at every site that emits the `EXCEPTD_KEYS_ROTATED_OVERRIDE` warning. `NODE_NO_WARNINGS=1` no longer silences security-relevant audit events.
100
+ - **`refresh-network` outer try/catch narrowed.** Previously a `try { ... } catch { /* warn-and-continue */ }` block silently absorbed any error from the inner pin-check emit. The catch now swallows only `ENOENT` / `EACCES` from the pin loader; every other error hard-fails with `process.exitCode = 5`.
101
+ - **`verify-shipped-tarball.js`** KEYS_ROTATED override now emits the `EXCEPTD_KEYS_ROTATED_OVERRIDE` warning code, matching the three other pin-loader sites.
102
+
103
+ ### Cache integrity
104
+
105
+ - **`readCachedJson` verifies SHA-256** against `_index.json.entries[<source>/<id>].sha256` for every cache read. Mismatch refuses with structured `{ ok: false, error: 'cache-integrity', _exceptd_exit_code: 4 }`. Closes the local-attacker primitive where swapping cached payloads via `.cache/upstream/` injected attacker-controlled CVE intel that the maintainer's signing key then attested as authoritative.
106
+ - **`_index.json` signed via Ed25519 at prefetch time** (sidecar `_index.json.sig`); `--from-cache` consumers verify before reading. When `.keys/private.pem` is absent at prefetch time, the cache ships unsigned and the consume path warns. `--force-stale` is the operator escape for caches predating this gate.
107
+ - **`--from-cache` max-age check (7-day default)** with `--force-stale` / `EXCEPTD_FORCE_STALE=1` override. Catalog freshness is a Hard Rule #1 obligation; a 6-month-old cache writing `last_verified: TODAY` into the catalog manufactures false freshness.
108
+ - **`--from-fixture` gated behind `EXCEPTD_TEST_HARNESS=1`.** The flag passes fixture diffs through as authoritative with no integrity check; outside the test harness, refuses with a clear hint.
109
+ - **Future-dated `fetched_at`** treated as poison (negative age → reject).
110
+
111
+ ### Air-gap defenses
112
+
113
+ - **`refresh --network`, `doctor --registry-check`, `auto-discovery` Datatracker fetch, and `prefetch`** now honor `--air-gap` and `EXCEPTD_AIR_GAP=1`. The four leak paths cycle 8 identified are closed; operators in regulated environments get a real guarantee.
114
+ - **`--air-gap` flag and `EXCEPTD_AIR_GAP=1` env are equivalent** at every site that consumes either.
115
+ - **AI-consumer telemetry advisory.** When `--air-gap` is active, exceptd emits a one-time stderr advisory noting that the operator's AI agent may still call its model API. Routed through stderr so JSON-mode consumers see only structured stdout.
116
+ - **Air-gap completeness lint rule** in `lib/lint-skills.js` flags playbook artifacts whose `source` contains a network pattern (`https://`, `http://`, `gh api`, `gh release`, `curl`, `wget`, `fetch`) without `air_gap_alternative`.
117
+ - **Playbook schema constraint**: when `_meta.air_gap_mode === true`, every artifact with a network-shaped `source` MUST declare `air_gap_alternative` (JSON Schema 2020-12 `if/then`).
118
+
119
+ ### `attest verify` replay isolation
120
+
121
+ - **`attest verify <session-id>` partitions `kind: replay` records out of `results[]` into a new `replay_results[]` array.** Previously every JSON file under `.exceptd/attestations/<sid>/` was sidecar-verified and counted in `results[]`, inflating "N/N verified" counts and elevating replay tamper to exit 6 indistinguishably from attestation tamper.
122
+ - **Attestation tamper still exits 6.** Replay tamper sets `body.replay_tamper = true` + `body.warnings = [...]` and exits 0 — replay records are an audit trail, distinct in remediation from a tampered attestation.
123
+ - **Both arrays sorted for determinism** (attestations by `captured_at`, replays by `replayed_at`).
124
+ - **`attest diff --against`** prefers `attestation.json` over filesystem-order; skips replay records when selecting the comparison target.
125
+
126
+ ### Concurrency + exit-code surface
127
+
128
+ - **`lib/exit-codes.js` is the single source of truth.** Every `process.exitCode = N` site in `bin/exceptd.js` references `EXIT_CODES.LOCK_CONTENTION` / `STORAGE_EXHAUSTED` / `SESSION_ID_COLLISION` etc. instead of bare numbers. `exceptd doctor --exit-codes` dumps the map so docs cannot drift from runtime.
129
+ - **Exit-code 3 overload split.** Pre-v0.12.24 exit 3 meant both "session-id collision" (cmdRun) AND "ran-but-no-evidence" (cmdCi). Session-id collision now uses `SESSION_ID_COLLISION = 7`; ran-but-no-evidence keeps `RAN_NO_EVIDENCE = 3`.
130
+ - **`cmdRunMulti` propagates `lock_contention`** from per-playbook persist failure into the aggregate `process.exitCode = 8`. Previously the aggregate gate collapsed every persist failure to 1, hiding the lock-busy signal that callers retry on.
131
+ - **ENOSPC vs EEXIST distinction.** Storage exhaustion (`ENOSPC` / `EROFS` / `EDQUOT`) on lockfile or attestation write now sets `process.exitCode = 9 STORAGE_EXHAUSTED` with `body.storage_exhausted = true`. Operator runbooks looping on 8/retry through a full disk now branch on the right signal.
132
+ - **`run --all` aggregate precedence:** `LOCK_CONTENTION > STORAGE_EXHAUSTED > GENERIC_FAILURE`.
133
+
134
+ ### Bundle correctness (CSAF / SARIF / OpenVEX)
135
+
136
+ - **CSAF `product_tree.branches[]`** synthesised as a 3-level vendor → product_name → product_version hierarchy from either a new optional `affected_products[{ vendor, product, version }]` catalog field or a heuristic parse of the existing `affected_components[]` strings. Closes the ENISA conformance gap.
137
+ - **Strict CVSS 3.x vector parse.** `parseCvss31Vector(v)` accepts both versions CSAF 2.0 cvss_v3 permits (3.0 and 3.1) and validates the full grammar. Malformed vectors (`AV:X`, unknown metric values, out-of-order metrics) and unsupported versions (2.0, 4.0) skip the `cvss_v3` block and emit `csaf_cvss_invalid` to `runtime_errors[]`.
138
+ - **OpenVEX URN routing by id prefix.** `vulnIdToUrn(id)` routes `CVE-*` → `urn:cve:`, `GHSA-*` → `urn:ghsa:`, `RUSTSEC-*` → `urn:rustsec:`, `MAL-*` → `urn:malicious-package:`, everything else → `urn:exceptd:advisory:`. Pre-v0.12.24, GHSA/RUSTSEC/MAL all emitted under `urn:cve:` and downstream VEX ingesters resolved them against the CVE List incorrectly.
139
+ - **OpenVEX `status: fixed`** carries an `impact_statement` trail referencing the operator's evidence (e.g. `Operator verified fixed via evidence_hash=<sha256[:16]>`).
140
+ - **`--tlp <CLEAR|GREEN|AMBER|AMBER+STRICT|RED>`** populates CSAF `document.distribution.tlp.label`. When omitted, the field is absent entirely. MISP / Trusted-Repository consumers gating on TLP no longer reject the document.
141
+ - **SARIF `invocations[].executionSuccessful`** reflects classification (`false` when inconclusive). Pre-v0.12.24 hard-coded `true`.
142
+
143
+ ### Engine internals
144
+
145
+ - **`runtime_errors[]` capped + per-kind deduped.** New helper `pushRunError(arr, entry, opts)` replaces 13 push sites. Per-kind cap defaults to 100; total cap 1000; overflow records as a `_truncated` sentinel. Closes the 39 MB worst-case attestation bloat under pathological catalog states.
146
+ - **`live_patch_tools[]` schema split.** New optional `vendor_update_paths[]` field separates true live-patch tools (kpatch, kGraft, Canonical Livepatch) from vendor-update mechanisms (npm yank, IDE update, package version pin). RWEP `live_patch_available` factor remains gated on the narrower `live_patch_tools[]`, so the score no longer over-credits vendor-update-only entries.
147
+
148
+ ### CLI surface
149
+
150
+ - **`attest prune <session-id>` verb** removes an attestation session. Modes: `--force` (specific session), `--all-older-than <days> --force` (bulk), `--playbook <id>` (scoped), `--dry-run` (list without delete). Refuses `.` / `..` / all-dots ids and paths that resolve outside the attestation root.
151
+ - **Levenshtein flag-typo suggestions.** Unknown flags trigger a per-verb allowlist lookup; suggestions fire at edit distance ≤ 2 AND ≤ flag.length/2. `--evidnce ev.json` now sees `{ ok: false, error: 'unknown flag --evidnce', suggested: 'evidence' }`.
152
+ - **Missing-value detection.** Value-bearing flags that parsed as `true` (i.e. no value) emit `--<flag> requires a value`.
153
+ - **Help-text completeness.** `run`, `ai-run`, `ingest`, `run-all` help blocks document `--vex` / `--evidence-dir` / `--attestation-root` / `--mode`. `ai-run --help` adds an exit-code table (0/1/3/8/9). `ci --help` exit-code table corrected to omit 6/8 (cmdCi cannot emit them). Top-level `exceptd help` adds unknown-verb exit 2. `attest --help` documents `--since` under `list`; corrects `export --format` enumeration to match implementation.
154
+ - **`discover` / `ask`** document "always exits 0" so CI gates branch on JSON shape rather than exit code.
155
+
156
+ ### Error-message UX
157
+
158
+ - **`dispatchPlaybook` catch-all, `cmdAiRun` runner-threw, `cmdLint` catch, `cmdReattest replay.reason` falsy path, `cmdRun` "no playbook resolved", `attest <subverb>` missing session-id** all wrap bare `e.message` with verb name + remediation hint pointing at the issue tracker.
159
+ - **Six sites of "playbook X has no directives"** consolidated into a shared helper.
160
+ - **JSON-mode stderr bypass sites** at `cmdRun` persist failure / `cmdIngest` persist failure / `cmdCi --format` validation route through `emitError` for consistent ok-false → exit-code mapping.
161
+
162
+ ### Hard Rule #5 — global-first quality
163
+
164
+ - **`framework.json`** `framework_lag_declaration` rewritten with substantive per-framework gaps (NIST CA-7, EU NIS2 Art.21(2), UK CAF Principle A, AU Essential 8 Strategy 1, ISO/IEC 27001:2022 A.5.1). The meta-playbook now models the pattern instead of paper-name-dropping the frameworks.
165
+ - **`containers.json`** AU clause: E8 Strategy 1 Application Control bound to OPA/Kyverno privileged-pod admission (replaces the prior "Macro Settings by analogy" mismatch).
166
+ - **`crypto-codebase.json`** UK CAF C.5 + PSTI gap explicit: CAF mandates outcome-tested cryptography but doesn't require PQC-by-default / constant-time / KDF minima; PSTI scope is connected products only.
167
+ - **`library-author.json`** CAF C1.b + E8 Strategy 5 specific gaps (no SLSA L3+ provenance requirement; admin-privilege restriction doesn't reach build-time signing-key access).
168
+ - **`secrets.json`** adds NIST IA-5 with detection-of-credentials-in-source gap; E8 alignment shifts to Strategy 1 Application Control (restricting CI agent secret-store reads) instead of MFA (which static bearer tokens bypass). Adds 4 AU `per_framework_gaps[]` entries (Strategy 1 / Strategy 4 / ISM-1546 / ISM-1559) with compliance-theater tests embedded.
169
+ - **`hardening.json`** adds NIS2 Art.21(2)(c) + DORA Art.9(4) hardening-attestation gap.
170
+
171
+ ### Operator-facing docs
172
+
173
+ - **`engines.node`** widened from `>=24.0.0` to `>=22.11.0`. Node 22 LTS through Apr 2027 is the corporate default; the prior pin excluded most enterprise installs.
174
+ - **Keywords** add `csaf-2.0`, `openvex`, `sarif`, `ed25519`, `provenance`, `attestation` (22 → 28 entries, alphabetised).
175
+ - **README install section** adds a "First run" snippet (`exceptd doctor --signatures` + fingerprint pin + npm provenance verify). New `agents/` description documents the markdown role-card scaffolding for skill authors.
176
+ - **CHANGELOG retroactive cleanup.** Operator-facing slot-token leakage removed from the v0.12.21 and v0.12.23 Internal sections.
177
+ - **`MAINTAINERS.md`** version-pinned subheadings collapsed into a single "High-trust skill paths" list.
178
+ - **Landing site (https://exceptd.com/)** refreshed: `softwareVersion: 0.12.24`, "35 jurisdictions" across every body-copy occurrence (was "34"), `exceptd plan` → `exceptd brief --all`, `exceptd scan` → `exceptd discover`, "13-gate predeploy" → "14-gate predeploy".
179
+
180
+ ### Internal — test infra hardening
181
+
182
+ - **`tests/_helpers/snapshot-restore.js`** new helper. `withFileSnapshot([paths], async () => {...})` wraps mutation tests; restoration fires on normal completion, thrown error, SIGINT, SIGTERM, and `process.exit`. Closes the historical "smoke test mutates state, SIGINT skips finally, leaves polluted file on disk" class.
183
+ - **20+ coincidence-passing `notEqual(r.status, 0)` test sites pinned** to exact exit codes across `predeploy-gate-coverage`, `operator-bugs`, `build-incremental`, `refresh-swarm`, `orchestrator-audit-f`, `cli-coverage`, `prefetch`.
184
+ - **`scripts/check-test-coverage.js` predeploy gate extended** with a `coincidence-assert` ban: any new `assert.notEqual(*.status, *)` site fails the gate unless the same line carries `// allow-notEqual: <reason>`.
185
+ - **14 `audit-*-fixes.test.js` files renamed** to behavior-framed names (`runtime-errors-and-vex-disposition`, `attestation-trust-boundary`, `csaf-bundle-correctness`, `cli-flag-validation`, `playbook-runner-error-paths`, `framework-gap-completeness`, `rwep-scoring-edge-cases`, `cli-subverb-dispatch`, `openvex-emission`, `predeploy-gate-coverage`, `cli-exit-codes`, `playbook-schema-validation`, `attestation-signature-roundtrip`, `cve-catalog-shape`).
186
+ - **New coverage**: `cli-playbook-traversal.test.js`, `attest-verify-replay-isolation.test.js`, `cmd-run-multi-lock-contention.test.js`, `openvex-urn-routing.test.js`, `lib-exit-codes.test.js`, `lib-id-validation.test.js`, `lib-flag-suggest.test.js`.
187
+
188
+ Test count: 995 → 1043 pass (5 skipped). Predeploy gates: 14/14. Skills: 38/38 signed; manifest envelope signed.
189
+
3
190
  ## 0.12.23 — 2026-05-15
4
191
 
5
192
  **Patch: doc-vs-code reconciliation, trust-chain pin loader hardening, attest list/show replay isolation, global-first framework coverage backfill.**
@@ -39,8 +226,8 @@
39
226
 
40
227
  ### Internal
41
228
 
42
- - **Source-comment slot-token scrub broadened** to cover bare audit slot-tokens (`KK P1-N`, `R-F8`, `S P1-A`, etc.) without the leading `audit` prefix. Previous scrubs only matched `(audit|Audit)\s+[A-Z]+`; the new sweep covers comment-only references across `bin/`, `lib/`, `scripts/`, and `tests/`. Test logic and code logic untouched.
43
- - **`tests/audit-mm-nn-fixes.test.js` tightened** the UTF-16BE odd-length-payload refusal test was asserting `notEqual(r.status, 0)`, the exact coincidence-passing-tests anti-pattern the project rule explicitly forbids. Changed to `assert.equal(r.status, 1)`.
229
+ - **Internal code comments stripped of stray maintenance-tracking tokens (no behavior change).**
230
+ - **Exit-code assertion in the UTF-16BE odd-length-payload test tightened** from `notEqual(r.status, 0)` to `assert.equal(r.status, 1)` per project anti-coincidence rule.
44
231
 
45
232
  Test count and predeploy gates land alongside this entry; see the predeploy log on the release commit.
46
233
 
@@ -173,7 +360,7 @@ UK CAF + AU Essential 8 / ISM entries added to the framework-control-gap declara
173
360
 
174
361
  ### Source comments
175
362
 
176
- Cleanup pass across `bin/`, `lib/`, `scripts/` — comments now describe behavior, not work-stream.
363
+ Source comments rewritten to describe behavior.
177
364
 
178
365
  Test count: 840 → 941 (938 pass + 3 skipped). Predeploy gates: 14/14. Skills: 38/38 signed; manifest envelope signed.
179
366
 
package/README.md CHANGED
@@ -36,7 +36,7 @@ Pre-1.0. Latest release lives on [GitHub Releases](https://github.com/blamejs/ex
36
36
 
37
37
  **v0.11.0 collapses the 21-verb CLI into 11 canonical verbs** + flips the default output to human-readable. The new surface: `discover` (scan cwd → recommend playbooks), `brief` (unified info doc, replaces plan + govern + direct + look), `run` (phases 4-7, with flat or nested submission shape, auto-detect cwd context), `ai-run` (JSONL streaming variant for AI conversational flow), `attest` (subverbs: list / show / export / verify / diff — replaces reattest + list-attestations), `doctor` (one-shot health check — signatures + currency + cve/rfc validation + signing status), `ci` (one-shot CI gate, exit-2 on detected or rwep ≥ escalate), `ask` (plain-English routing), `lint` (pre-flight submission shape check). Attestation root moved from cwd-relative `.exceptd/` to `~/.exceptd/attestations/<repo-or-host-tag>/`. v0.10.x verbs (`plan`/`govern`/`direct`/`look`/`scan`/`dispatch`/`currency`/`verify`/`validate-cves`/`validate-rfcs`/`watchlist`/`prefetch`/`build-indexes`/`ingest`/`reattest`/`list-attestations`) still work via one-time deprecation banner — scheduled for removal in v0.13.
38
38
 
39
- **v0.11.1-0.11.7 stability arc** — 30+ operator-reported items fixed across the v0.11.x line: mutex filesystem lockfile, `--vex` filter, `--ci` exit-code gating, `--diff-from-latest`, `--operator`/`--ack` attestation binding, `--format <fmt>` actually transforms output for run + ci, `ask` synonym routing, `lint` shares normalize contract with runner, CSAF/SARIF/OpenVEX bundles include indicator hits + framework gaps (was: empty for posture-only playbooks), CSAF current_release_date populated, SARIF rule definitions for every ruleId, `doctor --fix` for missing private key, `--strict-preconditions` flag, default human output for `attest list`/`lint` on TTY. Permanent regression suite at `tests/operator-bugs.test.js` (35 named test cases) — re-introductions caught at `npm test`, not at user re-report.
39
+ **v0.11 series** — CLI ergonomics and signature-verify hardening: mutex filesystem lockfile, `--vex` filter, `--ci` exit-code gating, `--diff-from-latest`, `--operator`/`--ack` attestation binding, `--format <fmt>` transforms output for `run` and `ci`, `ask` synonym routing, `lint` shares the normalize contract with the runner, CSAF/SARIF/OpenVEX bundles include indicator hits and framework gaps for posture-only playbooks, CSAF `current_release_date` populated, SARIF rule definitions for every ruleId, `doctor --fix` repairs a missing private key, `--strict-preconditions` flag, default human output for `attest list` and `lint` on TTY. Regression coverage at `tests/operator-bugs.test.js` catches re-introductions at `npm test`.
40
40
 
41
41
  ---
42
42
 
@@ -147,6 +147,15 @@ npm install -g @blamejs/exceptd-skills
147
147
  exceptd help
148
148
  ```
149
149
 
150
+ First run — verify the signing chain and pin the public-key fingerprint for out-of-band checks:
151
+
152
+ ```bash
153
+ exceptd doctor --signatures # verify Ed25519 chains (38/38 expected)
154
+ cat $(exceptd path)/keys/EXPECTED_FINGERPRINT # pin fingerprint for OOB verify
155
+ ```
156
+
157
+ Verify on npm: `npm view @blamejs/exceptd-skills@<version> dist.signatures` shows the SLSA v1 provenance attestation.
158
+
150
159
  Air-gapped operation: run `exceptd refresh --prefetch` on a connected host, copy the resulting `.cache/upstream/` to the airgap, run `exceptd refresh --from-cache <path> --apply` over there. The vendored upstream snapshots replace every network call.
151
160
 
152
161
  Fresh-disclosure workflow (v0.12.0): the nightly auto-PR job pulls KEV / NVD / EPSS / IETF / **GHSA** (added in v0.12.0) / **OSV** (added in v0.12.10). KEV typically takes days; NVD ~10 days; GHSA fires within hours of disclosure and covers npm + PyPI + Maven + Go + NuGet + …; OSV aggregates the OSSF Malicious Packages dataset (`MAL-*` keys) + Snyk + RustSec + Mageia + Ubuntu USN + Go Vuln DB + PYSEC + UVI on top of GHSA — useful for malicious-package compromises that don't have CVEs yet (`exceptd refresh --advisory MAL-2026-3083`). New IDs land as drafts (`_auto_imported: true`, `_draft: true`) that the catalog validator treats as warnings, not errors — operators get the fresh entry immediately, editorial review (framework gaps, IoCs, ATLAS/ATT&CK refs) follows via `exceptd refresh --curate <ID>`. For "I want this advisory today, not tomorrow": `exceptd refresh --advisory <CVE-or-GHSA-or-MAL-or-SNYK-or-RUSTSEC-ID> --apply`.
@@ -380,6 +389,10 @@ If your tool has a conventional auto-load filename not listed here and you'd lik
380
389
 
381
390
  Regenerate with `exceptd build-indexes` (full) or `exceptd build-indexes --changed --parallel` (incremental).
382
391
 
392
+ ## For skill authors — `agents/`
393
+
394
+ The `agents/` directory ships markdown role cards documenting authoring conventions for contributors writing new skills or playbooks. The cards are reference material for humans and AI assistants editing the repo; the CLI runtime does not load them. Operators consuming `@blamejs/exceptd-skills` can ignore the directory.
395
+
383
396
  ## Data catalogs
384
397
 
385
398
  All skills pull from `data/`. Cross-validated against canonical upstream sources via `exceptd refresh` / `exceptd doctor --cves` / `exceptd doctor --rfcs`.