@blamejs/exceptd-skills 0.11.14 → 0.12.0
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.
- package/CHANGELOG.md +110 -0
- package/bin/exceptd.js +17 -0
- package/data/_indexes/_meta.json +7 -7
- package/data/_indexes/activity-feed.json +2 -2
- package/data/_indexes/catalog-summaries.json +2 -2
- package/data/_indexes/chains.json +17 -0
- package/data/_indexes/section-offsets.json +25 -25
- package/data/_indexes/token-budget.json +9 -9
- package/data/cve-catalog.json +114 -0
- package/data/playbooks/mcp.json +17 -4
- package/data/playbooks/sbom.json +121 -4
- package/data/zeroday-lessons.json +93 -0
- package/keys/public.pem +1 -1
- package/lib/cve-curation.js +274 -0
- package/lib/refresh-external.js +172 -1
- package/lib/source-ghsa.js +259 -0
- package/lib/validate-cve-catalog.js +22 -5
- package/manifest-snapshot.json +1 -1
- package/manifest.json +40 -40
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
- package/skills/supply-chain-integrity/skill.md +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,115 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.12.0 — 2026-05-13
|
|
4
|
+
|
|
5
|
+
**Minor: catalog freshness from minutes-old disclosures, not days.**
|
|
6
|
+
|
|
7
|
+
Today's refresh sources (KEV / NVD / EPSS / IETF / MITRE) don't see a fresh-disclosure npm worm. KEV listing takes days; NVD takes ~10 days. The CVE-2026-45321 TanStack worm was caught publicly within 20 minutes — but the only feed that fired in that window was the GitHub Advisory Database. v0.12.0 adds GHSA as a refresh source, plus operator-driven single-advisory seeding, plus an editorial-enrichment helper.
|
|
8
|
+
|
|
9
|
+
### GHSA as a refresh source
|
|
10
|
+
|
|
11
|
+
`exceptd refresh` now pulls from GitHub Advisory Database (covers npm, PyPI, RubyGems, Maven, NuGet, Go, Composer, Swift, Erlang, Pub, Rust). Unauthenticated 60 req/hr; authenticated 5000 req/hr via `GITHUB_TOKEN` env var. New CVE IDs land as **drafts** flagged `_auto_imported: true` + `_draft: true`. The strict catalog validator treats drafts as warnings, not errors — so the nightly auto-PR pipeline can ship them without blocking on editorial review. Framework gaps + IoCs + ATLAS/ATT&CK refs are explicit nulls awaiting human or AI-assisted enrichment.
|
|
12
|
+
|
|
13
|
+
(Note: npm Inc. does not publish a standalone JSON advisory feed; npm advisories are surfaced via GHSA. Adding `npm-advisories` as a separate source would duplicate GHSA data with no fidelity gain.)
|
|
14
|
+
|
|
15
|
+
### `exceptd refresh --advisory <id>`
|
|
16
|
+
|
|
17
|
+
Operator-driven single-advisory seeding. Accepts CVE-* or GHSA-* identifiers. Fetches the advisory from GHSA, normalizes to the catalog draft shape, prints (default) or writes (`--apply`). Always exits **3** ("draft prepared, editorial review pending") so CI pipelines surface the next step.
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
exceptd refresh --advisory CVE-2026-45321 # dry-run, prints draft
|
|
21
|
+
exceptd refresh --advisory CVE-2026-45321 --apply # writes draft into data/cve-catalog.json
|
|
22
|
+
exceptd refresh --advisory GHSA-xxxx-xxxx-xxxx --json # JSON output
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Refuses to overwrite a human-curated entry. Honors `EXCEPTD_GHSA_FIXTURE` env var for offline tests.
|
|
26
|
+
|
|
27
|
+
### `exceptd refresh --curate <CVE-ID>`
|
|
28
|
+
|
|
29
|
+
Editorial-enrichment helper. Reads the draft entry from `data/cve-catalog.json`, cross-references against `data/atlas-ttps.json` + `data/attack-ttps.json` + `data/cwe-catalog.json` + `data/framework-control-gaps.json`, and emits structured **editorial questions** — one per null field — each with ranked candidates and a specific ASK for the reviewer.
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
{
|
|
33
|
+
"editorial_questions": [
|
|
34
|
+
{
|
|
35
|
+
"field": "atlas_refs",
|
|
36
|
+
"current_value": [],
|
|
37
|
+
"candidates": [{"id": "AML.T0010", "score": 68, "reason": "..."}],
|
|
38
|
+
"ask": "Which MITRE ATLAS techniques are present in the attack chain?"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"field": "framework_control_gaps",
|
|
42
|
+
"ask": "Which framework controls CLAIM to cover this CVE's category, and where do they fall short? Per AGENTS.md Hard Rule #6, every framework finding must include a test that distinguishes paper compliance from actual security."
|
|
43
|
+
},
|
|
44
|
+
...
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Pure heuristic — deterministic keyword-overlap scoring against existing catalogs. The reviewer (human or AI assistant) makes the final call on each candidate. Always exits **3** because editorial review is, by definition, pending.
|
|
50
|
+
|
|
51
|
+
(The natural-language form `exceptd run cve-curation --advisory <id>` — wrapping this helper in a full seven-phase playbook with GRC closure — is scoped for v0.13. The helper itself ships in v0.12 so operators can use it now.)
|
|
52
|
+
|
|
53
|
+
### Catalog schema
|
|
54
|
+
|
|
55
|
+
- `data/cve-catalog.json` entries may now carry `_auto_imported`, `_draft`, `_draft_reason`, `_source_ghsa_id`, `_source_published_at` fields.
|
|
56
|
+
- `lib/validate-cve-catalog.js` recognizes drafts: prints them as `DRAFT` lines (not `FAIL`), does not exit-fail. The summary line includes a `<N> draft(s) (auto-imported)` count.
|
|
57
|
+
- `lib/schemas/cve-catalog.schema.json` is unchanged; the draft fields are absorbed by `additionalProperties: true`.
|
|
58
|
+
|
|
59
|
+
### Tests
|
|
60
|
+
|
|
61
|
+
7 new regression cases. 366 total. Coverage: ghsa fixture fetch, advisory normalization (draft shape + cisa_kev_pending heuristic for critical), `refresh --advisory` dry-run + apply paths, `refresh --curate` editorial-question generation, refusal-on-human-curated, validator draft-tolerance.
|
|
62
|
+
|
|
63
|
+
### Operator workflow
|
|
64
|
+
|
|
65
|
+
The end-to-end flow for a fresh-disclosure CVE the nightly job hasn't caught yet:
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
$ exceptd refresh --advisory CVE-2026-XXXXX --apply # seeds draft from GHSA
|
|
69
|
+
$ exceptd refresh --curate CVE-2026-XXXXX # surfaces editorial questions + candidates
|
|
70
|
+
# review the questions, fill the catalog entry, add a zeroday-lessons.json entry,
|
|
71
|
+
# remove _auto_imported and _draft flags, then:
|
|
72
|
+
$ npm run predeploy # strict gate now passes
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The nightly auto-PR mechanism handles the GHSA pull automatically; this surface is for "I want this CVE today, not tomorrow."
|
|
76
|
+
|
|
77
|
+
## 0.11.15 — 2026-05-13
|
|
78
|
+
|
|
79
|
+
**Patch: CVE-2026-45321 (Mini Shai-Hulud TanStack npm worm) — catalog + playbook + IoC sweep.**
|
|
80
|
+
|
|
81
|
+
Adds detection for the npm supply-chain worm disclosed 2026-05-11 (84 malicious versions across 42 `@tanstack/*` packages, including `@tanstack/react-router` at ~12M weekly downloads, CVSS 9.6). The novel category: first documented npm package shipping VALID SLSA provenance while being malicious. Provenance proves which pipeline built the artifact, not that the pipeline behaved as intended.
|
|
82
|
+
|
|
83
|
+
### Catalog
|
|
84
|
+
|
|
85
|
+
- `data/cve-catalog.json` — new entry `CVE-2026-45321` with full RWEP scoring (78), the three chained primitives (`pull_request_target` co-resident with `id-token: write` and shared `actions/cache`), payload IoCs, persistence IoCs (`.claude/settings.json` SessionStart hooks, `.vscode/tasks.json` folder-open hooks, macOS LaunchAgents, Linux systemd-user units), framework-gap analysis (SLSA L3 insufficient, NIST 800-218 SSDF PS.3/PO.3 gap), and the destructive-on-revocation behavior.
|
|
86
|
+
|
|
87
|
+
### Playbook detections (sbom)
|
|
88
|
+
|
|
89
|
+
- `tanstack-worm-payload-files` — find `node_modules/@tanstack/*/router_init.js` or `router_runtime.js`
|
|
90
|
+
- `tanstack-worm-resolved-during-publish-window` — lockfile entries resolved 2026-05-11T19:20Z..19:26Z
|
|
91
|
+
- `agent-persistence-claude-session-start-hook` — non-owner SessionStart hooks
|
|
92
|
+
- `agent-persistence-vscode-folder-open-task` — folder-open tasks running staged setup scripts
|
|
93
|
+
- `agent-persistence-os-level` — macOS LaunchAgents + Linux systemd-user units referencing in-repo `.mjs`
|
|
94
|
+
- `ci-cache-poisoning-co-residency` — repo has `pull_request_target` + `id-token: write` + shared `actions/cache` (architectural pre-condition, even without payload)
|
|
95
|
+
- `npm-registry-no-cooldown` — project consumes npm but `.npmrc` lacks `before=` or `minimumReleaseAge=`
|
|
96
|
+
|
|
97
|
+
### Playbook detections (mcp)
|
|
98
|
+
|
|
99
|
+
- Same `agent-persistence-*` indicators on the agentic-tooling side. MCP playbook covers the persistence vector; SBOM covers the supply-chain root.
|
|
100
|
+
|
|
101
|
+
### Skill update
|
|
102
|
+
|
|
103
|
+
- `skills/supply-chain-integrity/SKILL.md` — adds the CVE-2026-45321 case at the top of Threat Context with the chained-primitives explanation and the new SLSA-L3-insufficient framing.
|
|
104
|
+
|
|
105
|
+
### Eating own dogfood
|
|
106
|
+
|
|
107
|
+
- `.npmrc` — adds `before=72h` + `minimumReleaseAge=4320` so this repo refuses fresh-publish installs. Survives downgrade to older npm via both flags.
|
|
108
|
+
|
|
109
|
+
### threat_currency_score bumps
|
|
110
|
+
|
|
111
|
+
- `sbom` 95 → 97, `mcp` 96 → 97, both with `last_threat_review: 2026-05-13`.
|
|
112
|
+
|
|
3
113
|
## 0.11.14 — 2026-05-13
|
|
4
114
|
|
|
5
115
|
**Patch: items 129-134 + freshness surface — claims-vs-reality gap closure + opt-in registry-check.**
|
package/bin/exceptd.js
CHANGED
|
@@ -72,6 +72,7 @@ const COMMANDS = {
|
|
|
72
72
|
prefetch: () => path.join(PKG_ROOT, "lib", "prefetch.js"),
|
|
73
73
|
refresh: () => path.join(PKG_ROOT, "lib", "refresh-external.js"),
|
|
74
74
|
"refresh-network": () => path.join(PKG_ROOT, "lib", "refresh-network.js"),
|
|
75
|
+
"refresh-curate": () => path.join(PKG_ROOT, "lib", "cve-curation.js"),
|
|
75
76
|
"build-indexes": () => path.join(PKG_ROOT, "scripts", "build-indexes.js"),
|
|
76
77
|
verify: () => path.join(PKG_ROOT, "lib", "verify.js"),
|
|
77
78
|
scan: () => path.join(PKG_ROOT, "orchestrator", "index.js"),
|
|
@@ -252,9 +253,19 @@ v0.11.0 canonical surface
|
|
|
252
253
|
catalog snapshot from npm registry,
|
|
253
254
|
verify against local keys/public.pem,
|
|
254
255
|
swap data/ in place (no CLI/lib reload)
|
|
256
|
+
--advisory <id> (v0.12.0) seed a catalog entry from a
|
|
257
|
+
CVE-* or GHSA-* ID via GitHub Advisory
|
|
258
|
+
Database. Writes draft with
|
|
259
|
+
_auto_imported:true. Use --apply to
|
|
260
|
+
write to disk.
|
|
261
|
+
--curate <CVE-ID> (v0.12.0) emit editorial questions +
|
|
262
|
+
ranked candidates (ATLAS/ATT&CK/CWE/
|
|
263
|
+
framework gaps) for a draft entry.
|
|
255
264
|
--prefetch populate offline cache
|
|
256
265
|
--from-cache consume offline cache
|
|
257
266
|
--indexes-only rebuild indexes only
|
|
267
|
+
Sources: kev|epss|nvd|rfc|pins|ghsa (v0.12.0).
|
|
268
|
+
ghsa drafts pass validator as warnings.
|
|
258
269
|
|
|
259
270
|
v0.10.x compatibility (will be removed in v0.12)
|
|
260
271
|
────────────────────────────────────────────────
|
|
@@ -414,6 +425,12 @@ function main() {
|
|
|
414
425
|
// data slice without requiring a full package upgrade.
|
|
415
426
|
effectiveCmd = "refresh-network";
|
|
416
427
|
effectiveRest = rest.filter(a => a !== "--network");
|
|
428
|
+
} else if (cmd === "refresh" && rest.includes("--curate")) {
|
|
429
|
+
// v0.12.0: --curate <CVE-ID> emits editorial questions + ranked
|
|
430
|
+
// candidates (atlas/attack/cwe/framework) for a draft catalog entry.
|
|
431
|
+
// Operator or AI assistant fills the null editorial fields.
|
|
432
|
+
effectiveCmd = "refresh-curate";
|
|
433
|
+
effectiveRest = rest;
|
|
417
434
|
}
|
|
418
435
|
|
|
419
436
|
const resolver = COMMANDS[effectiveCmd];
|
package/data/_indexes/_meta.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema_version": "1.1.0",
|
|
3
|
-
"generated_at": "2026-05-13T02:
|
|
3
|
+
"generated_at": "2026-05-13T02:34:42.448Z",
|
|
4
4
|
"generator": "scripts/build-indexes.js",
|
|
5
5
|
"source_count": 49,
|
|
6
6
|
"source_hashes": {
|
|
7
|
-
"manifest.json": "
|
|
7
|
+
"manifest.json": "31cfbef4aa2a73ae93de1837209c958f5318fadbfc4481f06459617048fec44c",
|
|
8
8
|
"data/atlas-ttps.json": "1500b5830dab070c4252496964a8c0948e1052a656e2c7c6e1efaf0350645e13",
|
|
9
|
-
"data/cve-catalog.json": "
|
|
9
|
+
"data/cve-catalog.json": "e9a3a4ce988caa051e50a467f1cd9c0dcbf9e8f6f3e9522610baf196217b7bdc",
|
|
10
10
|
"data/cwe-catalog.json": "c3367d469b4b3d31e4c56397dd7a8305a0be338ecd85afa27804c0c9ce12157b",
|
|
11
11
|
"data/d3fend-catalog.json": "b5cd14669e2a931d0df81bb8402f3c8ac08b0d2613e595eaecd8cc4631a57587",
|
|
12
12
|
"data/dlp-controls.json": "8ea8d907aea0a2cfd772b048a62122a322ba3284a5c36a272ad5e9d392564cb5",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"data/framework-control-gaps.json": "25db4d0cc9e6242e1143494178393ae8eab3384672ca0d685bd55c537f028c83",
|
|
15
15
|
"data/global-frameworks.json": "84fd19061f052e4ccf66308a7b8d3fd38e00325e97e9e5e19e4d9b302c128957",
|
|
16
16
|
"data/rfc-references.json": "23ffeb970af5403e9a733844dcea9b45cbae689623085f030dec826c492682e3",
|
|
17
|
-
"data/zeroday-lessons.json": "
|
|
17
|
+
"data/zeroday-lessons.json": "0840eacd580d4ee5bd7dc44ccea6d52bfa95096576af0ccf67132eea05bedd55",
|
|
18
18
|
"skills/kernel-lpe-triage/skill.md": "c00e0a77e8b7b1a1ebcb7267dd728b39ec2671d1260bf4f6a4842f10101a69b0",
|
|
19
19
|
"skills/ai-attack-surface/skill.md": "3f5c59f1823f1552efe8a5cb32656d34d6407609ddaa1eed254c263864563453",
|
|
20
20
|
"skills/mcp-agent-trust/skill.md": "716d0d65499f8be21e0389a06a1fcaf6abd1cd2e90f068cab54471dd67127f74",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"skills/attack-surface-pentest/skill.md": "f639b6d9c19def5908eddbbb79f0514e168e74661c0894b737d7c76cbb550841",
|
|
35
35
|
"skills/fuzz-testing-strategy/skill.md": "83b1929a0d1e09a58908b91125ebc91ff14323ab9acc9bab6c4b04903b69b837",
|
|
36
36
|
"skills/dlp-gap-analysis/skill.md": "041c4c6a5299057383b1d6bd4328c1ef578f8c5c6bade8750d339c7b51020027",
|
|
37
|
-
"skills/supply-chain-integrity/skill.md": "
|
|
37
|
+
"skills/supply-chain-integrity/skill.md": "94527929c150bf9bc7a5a61a596373d49a88ae9114adf841b2d3771e25fb8d51",
|
|
38
38
|
"skills/defensive-countermeasure-mapping/skill.md": "634f0805597a0ab417248a7413eed39b08afbc820e7c6bd257eebaa663d8990d",
|
|
39
39
|
"skills/identity-assurance/skill.md": "e8f3958ef8dd89f9276f2a62a0a1b418a206a3312bb8ff228729c8f358603dc7",
|
|
40
40
|
"skills/ot-ics-security/skill.md": "7c6eb389e7ace5b2c6e092f8dfcf4795ce1b0aefaa2738c6e383cb0fef4d6287",
|
|
@@ -67,13 +67,13 @@
|
|
|
67
67
|
"dlp_refs": 0
|
|
68
68
|
},
|
|
69
69
|
"trigger_table_entries": 453,
|
|
70
|
-
"chains_cve_entries":
|
|
70
|
+
"chains_cve_entries": 6,
|
|
71
71
|
"chains_cwe_entries": 34,
|
|
72
72
|
"jurisdictions_indexed": 29,
|
|
73
73
|
"handoff_dag_nodes": 38,
|
|
74
74
|
"summary_cards": 38,
|
|
75
75
|
"section_offsets_skills": 38,
|
|
76
|
-
"token_budget_total_approx":
|
|
76
|
+
"token_budget_total_approx": 334832,
|
|
77
77
|
"recipes": 8,
|
|
78
78
|
"jurisdiction_clocks": 29,
|
|
79
79
|
"did_ladders": 8,
|
|
@@ -172,7 +172,7 @@
|
|
|
172
172
|
"artifact": "data/cve-catalog.json",
|
|
173
173
|
"path": "data/cve-catalog.json",
|
|
174
174
|
"schema_version": "1.0.0",
|
|
175
|
-
"entry_count":
|
|
175
|
+
"entry_count": 6
|
|
176
176
|
},
|
|
177
177
|
{
|
|
178
178
|
"date": "2026-05-11",
|
|
@@ -349,7 +349,7 @@
|
|
|
349
349
|
"artifact": "data/zeroday-lessons.json",
|
|
350
350
|
"path": "data/zeroday-lessons.json",
|
|
351
351
|
"schema_version": "1.0.0",
|
|
352
|
-
"entry_count":
|
|
352
|
+
"entry_count": 6
|
|
353
353
|
},
|
|
354
354
|
{
|
|
355
355
|
"date": "2026-05-01",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"rebuild_after_days": 365,
|
|
41
41
|
"note": "Per-entry last_verified governs decay. Skills depending on this catalog must check entry freshness before high-stakes use."
|
|
42
42
|
},
|
|
43
|
-
"entry_count":
|
|
43
|
+
"entry_count": 6,
|
|
44
44
|
"sample_keys": [
|
|
45
45
|
"CVE-2026-31431",
|
|
46
46
|
"CVE-2026-43284",
|
|
@@ -216,7 +216,7 @@
|
|
|
216
216
|
"rebuild_after_days": 365,
|
|
217
217
|
"note": "Per-entry last_verified governs decay. Skills depending on this catalog must check entry freshness before high-stakes use."
|
|
218
218
|
},
|
|
219
|
-
"entry_count":
|
|
219
|
+
"entry_count": 6,
|
|
220
220
|
"sample_keys": [
|
|
221
221
|
"CVE-2026-31431",
|
|
222
222
|
"CVE-2025-53773",
|
|
@@ -1751,6 +1751,23 @@
|
|
|
1751
1751
|
]
|
|
1752
1752
|
}
|
|
1753
1753
|
},
|
|
1754
|
+
"CVE-2026-45321": {
|
|
1755
|
+
"name": "Mini Shai-Hulud TanStack npm worm",
|
|
1756
|
+
"rwep": 45,
|
|
1757
|
+
"cvss": 9.6,
|
|
1758
|
+
"cisa_kev": false,
|
|
1759
|
+
"epss_score": 0.78,
|
|
1760
|
+
"epss_percentile": 0.97,
|
|
1761
|
+
"referencing_skills": [],
|
|
1762
|
+
"chain": {
|
|
1763
|
+
"cwes": [],
|
|
1764
|
+
"atlas": [],
|
|
1765
|
+
"d3fend": [],
|
|
1766
|
+
"framework_gaps": [],
|
|
1767
|
+
"attack_refs": [],
|
|
1768
|
+
"rfc_refs": []
|
|
1769
|
+
}
|
|
1770
|
+
},
|
|
1754
1771
|
"CWE-787": {
|
|
1755
1772
|
"name": "Out-of-bounds Write",
|
|
1756
1773
|
"category": "Memory Safety",
|
|
@@ -1868,8 +1868,8 @@
|
|
|
1868
1868
|
},
|
|
1869
1869
|
"supply-chain-integrity": {
|
|
1870
1870
|
"path": "skills/supply-chain-integrity/skill.md",
|
|
1871
|
-
"total_bytes":
|
|
1872
|
-
"total_lines":
|
|
1871
|
+
"total_bytes": 39667,
|
|
1872
|
+
"total_lines": 320,
|
|
1873
1873
|
"frontmatter": {
|
|
1874
1874
|
"line_start": 1,
|
|
1875
1875
|
"line_end": 65,
|
|
@@ -1882,70 +1882,70 @@
|
|
|
1882
1882
|
"normalized_name": "threat-context",
|
|
1883
1883
|
"line": 69,
|
|
1884
1884
|
"byte_start": 1820,
|
|
1885
|
-
"byte_end":
|
|
1886
|
-
"bytes":
|
|
1885
|
+
"byte_end": 7211,
|
|
1886
|
+
"bytes": 5391,
|
|
1887
1887
|
"h3_count": 0
|
|
1888
1888
|
},
|
|
1889
1889
|
{
|
|
1890
1890
|
"name": "Framework Lag Declaration",
|
|
1891
1891
|
"normalized_name": "framework-lag-declaration",
|
|
1892
|
-
"line":
|
|
1893
|
-
"byte_start":
|
|
1894
|
-
"byte_end":
|
|
1892
|
+
"line": 88,
|
|
1893
|
+
"byte_start": 7211,
|
|
1894
|
+
"byte_end": 17694,
|
|
1895
1895
|
"bytes": 10483,
|
|
1896
1896
|
"h3_count": 1
|
|
1897
1897
|
},
|
|
1898
1898
|
{
|
|
1899
1899
|
"name": "TTP Mapping",
|
|
1900
1900
|
"normalized_name": "ttp-mapping",
|
|
1901
|
-
"line":
|
|
1902
|
-
"byte_start":
|
|
1903
|
-
"byte_end":
|
|
1901
|
+
"line": 133,
|
|
1902
|
+
"byte_start": 17694,
|
|
1903
|
+
"byte_end": 20822,
|
|
1904
1904
|
"bytes": 3128,
|
|
1905
1905
|
"h3_count": 0
|
|
1906
1906
|
},
|
|
1907
1907
|
{
|
|
1908
1908
|
"name": "Exploit Availability Matrix",
|
|
1909
1909
|
"normalized_name": "exploit-availability-matrix",
|
|
1910
|
-
"line":
|
|
1911
|
-
"byte_start":
|
|
1912
|
-
"byte_end":
|
|
1910
|
+
"line": 156,
|
|
1911
|
+
"byte_start": 20822,
|
|
1912
|
+
"byte_end": 25403,
|
|
1913
1913
|
"bytes": 4581,
|
|
1914
1914
|
"h3_count": 0
|
|
1915
1915
|
},
|
|
1916
1916
|
{
|
|
1917
1917
|
"name": "Analysis Procedure",
|
|
1918
1918
|
"normalized_name": "analysis-procedure",
|
|
1919
|
-
"line":
|
|
1920
|
-
"byte_start":
|
|
1921
|
-
"byte_end":
|
|
1919
|
+
"line": 173,
|
|
1920
|
+
"byte_start": 25403,
|
|
1921
|
+
"byte_end": 32860,
|
|
1922
1922
|
"bytes": 7457,
|
|
1923
1923
|
"h3_count": 4
|
|
1924
1924
|
},
|
|
1925
1925
|
{
|
|
1926
1926
|
"name": "Output Format",
|
|
1927
1927
|
"normalized_name": "output-format",
|
|
1928
|
-
"line":
|
|
1929
|
-
"byte_start":
|
|
1930
|
-
"byte_end":
|
|
1928
|
+
"line": 247,
|
|
1929
|
+
"byte_start": 32860,
|
|
1930
|
+
"byte_end": 34962,
|
|
1931
1931
|
"bytes": 2102,
|
|
1932
1932
|
"h3_count": 9
|
|
1933
1933
|
},
|
|
1934
1934
|
{
|
|
1935
1935
|
"name": "Compliance Theater Check",
|
|
1936
1936
|
"normalized_name": "compliance-theater-check",
|
|
1937
|
-
"line":
|
|
1938
|
-
"byte_start":
|
|
1939
|
-
"byte_end":
|
|
1937
|
+
"line": 287,
|
|
1938
|
+
"byte_start": 34962,
|
|
1939
|
+
"byte_end": 37250,
|
|
1940
1940
|
"bytes": 2288,
|
|
1941
1941
|
"h3_count": 0
|
|
1942
1942
|
},
|
|
1943
1943
|
{
|
|
1944
1944
|
"name": "Defensive Countermeasure Mapping",
|
|
1945
1945
|
"normalized_name": "defensive-countermeasure-mapping",
|
|
1946
|
-
"line":
|
|
1947
|
-
"byte_start":
|
|
1948
|
-
"byte_end":
|
|
1946
|
+
"line": 303,
|
|
1947
|
+
"byte_start": 37250,
|
|
1948
|
+
"byte_end": 39667,
|
|
1949
1949
|
"bytes": 2417,
|
|
1950
1950
|
"h3_count": 0
|
|
1951
1951
|
}
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
"schema_version": "1.0.0",
|
|
4
4
|
"tokenizer_note": "Character-density approximation: 1 token ≈ 4 chars. This is the canonical rule-of-thumb for OpenAI tokenizers on English+technical text. Claude's tokenizer is typically more efficient on prose; treat this as an upper-bound budget for both. Consumers with stricter precision needs should re-tokenize with their own tokenizer.",
|
|
5
5
|
"approx_chars_per_token": 4,
|
|
6
|
-
"total_chars":
|
|
7
|
-
"total_approx_tokens":
|
|
6
|
+
"total_chars": 1339318,
|
|
7
|
+
"total_approx_tokens": 334832,
|
|
8
8
|
"skill_count": 38
|
|
9
9
|
},
|
|
10
10
|
"skills": {
|
|
@@ -1090,16 +1090,16 @@
|
|
|
1090
1090
|
},
|
|
1091
1091
|
"supply-chain-integrity": {
|
|
1092
1092
|
"path": "skills/supply-chain-integrity/skill.md",
|
|
1093
|
-
"bytes":
|
|
1094
|
-
"chars":
|
|
1095
|
-
"lines":
|
|
1096
|
-
"approx_tokens":
|
|
1093
|
+
"bytes": 39667,
|
|
1094
|
+
"chars": 39533,
|
|
1095
|
+
"lines": 320,
|
|
1096
|
+
"approx_tokens": 9883,
|
|
1097
1097
|
"approx_chars_per_token": 4,
|
|
1098
1098
|
"sections": {
|
|
1099
1099
|
"threat-context": {
|
|
1100
|
-
"bytes":
|
|
1101
|
-
"chars":
|
|
1102
|
-
"approx_tokens":
|
|
1100
|
+
"bytes": 5391,
|
|
1101
|
+
"chars": 5377,
|
|
1102
|
+
"approx_tokens": 1344
|
|
1103
1103
|
},
|
|
1104
1104
|
"framework-lag-declaration": {
|
|
1105
1105
|
"bytes": 10483,
|
package/data/cve-catalog.json
CHANGED
|
@@ -492,5 +492,119 @@
|
|
|
492
492
|
}
|
|
493
493
|
],
|
|
494
494
|
"last_updated": "2026-05-11"
|
|
495
|
+
},
|
|
496
|
+
"CVE-2026-45321": {
|
|
497
|
+
"name": "Mini Shai-Hulud TanStack npm worm",
|
|
498
|
+
"type": "supply-chain-worm",
|
|
499
|
+
"cvss_score": 9.6,
|
|
500
|
+
"cvss_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H",
|
|
501
|
+
"cisa_kev": false,
|
|
502
|
+
"cisa_kev_date": null,
|
|
503
|
+
"cisa_kev_pending": true,
|
|
504
|
+
"cisa_kev_pending_reason": "Attack disclosed 2026-05-11. Active in-the-wild exploitation of 42 @tanstack/* packages with combined ~150M weekly downloads. CISA KEV listing expected within standard review window.",
|
|
505
|
+
"poc_available": true,
|
|
506
|
+
"poc_description": "Confirmed in-the-wild — 84 malicious versions published across 42 @tanstack/* packages between 2026-05-11 19:20-19:26 UTC. The worm itself IS the PoC; payload analysis published by multiple researchers within 20 minutes.",
|
|
507
|
+
"ai_discovered": false,
|
|
508
|
+
"ai_assisted_weaponization": false,
|
|
509
|
+
"ai_assisted_notes": "Attack methodology is engineering-grade — chained primitives across CI/CD, pnpm cache, and OIDC token handling. No evidence of AI-assisted exploit development; attribution: TeamPCP.",
|
|
510
|
+
"active_exploitation": "confirmed",
|
|
511
|
+
"affected": "Anyone consuming any of 42 @tanstack/* npm packages (router, table, form, store, virtual, etc.) — combined ~150M+ weekly downloads. @tanstack/react-router alone ships to ~12M weekly. Excludes @tanstack/react-query (not in the affected set).",
|
|
512
|
+
"affected_versions": [
|
|
513
|
+
"84 specific malicious versions published 2026-05-11 19:20-19:26 UTC across 42 @tanstack/* packages — all yanked; check `npm view <pkg> time` for the publish-time window. Any package-lock.json or pnpm-lock.yaml resolved during that window is suspect."
|
|
514
|
+
],
|
|
515
|
+
"vector": "Three chained primitives — none sufficient alone: (1) pull_request_target on TanStack's bundle-size.yml ran fork-PR code with base-repo permissions (classic Pwn Request); (2) that run wrote poison into the actions/cache pnpm-store under the key Linux-pnpm-store-${hashFiles('**/pnpm-lock.yaml')} that release.yml later restored; (3) on next main push, release.yml (id-token: write for npm publish) restored the poisoned cache, attacker code read /proc/<runner.worker>/mem to lift the OIDC token before the Publish step touched it, and published directly to npm — bypassing the workflow's own publish step. Result: malicious tarballs shipped with VALID SLSA provenance.",
|
|
516
|
+
"complexity": "high",
|
|
517
|
+
"complexity_notes": "Requires upstream maintainer to have (a) pull_request_target trigger on a non-publishing workflow with sufficient permissions, (b) cache that publish workflow later consumes, and (c) id-token: write scoped broadly enough that an in-process actor can scrape it. Each link is fixable individually; the chain is what's novel.",
|
|
518
|
+
"patch_available": true,
|
|
519
|
+
"patch_required_reboot": false,
|
|
520
|
+
"live_patch_available": true,
|
|
521
|
+
"live_patch_tools": [
|
|
522
|
+
"npm yank — registry has removed the malicious versions",
|
|
523
|
+
"Pin or rollback affected @tanstack/* packages in package-lock.json / pnpm-lock.yaml to a pre-2026-05-11-19:20Z resolved version",
|
|
524
|
+
"Set npm registry cooldown: .npmrc `before=72h` (npm 11+) or `minimumReleaseAge=4320` to refuse any fresh-publish under 72 hours"
|
|
525
|
+
],
|
|
526
|
+
"framework_control_gaps": {
|
|
527
|
+
"SLSA-L3": "FIRST documented npm package shipping valid SLSA provenance while being malicious — provenance only proves WHICH pipeline built the artifact, not that the pipeline BEHAVED AS INTENDED. SLSA L3 build integrity is necessary but insufficient against cache-poisoning attacks within the build.",
|
|
528
|
+
"NIST-800-53-SA-12": "Supply chain protection treats provenance + signing as the trust anchor. CVE-2026-45321 demonstrates both can be intact on a malicious package.",
|
|
529
|
+
"NIST-800-218-SSDF": "PS.3 + PO.3 don't address cache poisoning between sibling workflows in the same repo. SSDF presumes per-workflow trust isolation that GitHub Actions' shared actions/cache breaks.",
|
|
530
|
+
"EU-CRA-Art13": "Required vulnerability handling doesn't cover the case where the upstream maintainer is unwitting — the maintainer was a victim, not a participant.",
|
|
531
|
+
"NIS2-Art21-2d": "Supply chain risk management presumes detectable signal at consumption. Valid provenance neutralizes the standard consumer-side check.",
|
|
532
|
+
"DORA-Art28": "ICT third-party risk doesn't cover transitive cache poisoning in upstream CI/CD."
|
|
533
|
+
},
|
|
534
|
+
"atlas_refs": [
|
|
535
|
+
"AML.T0010",
|
|
536
|
+
"AML.T0018",
|
|
537
|
+
"AML.T0048"
|
|
538
|
+
],
|
|
539
|
+
"attack_refs": [
|
|
540
|
+
"T1195.002",
|
|
541
|
+
"T1078.004",
|
|
542
|
+
"T1574",
|
|
543
|
+
"T1059.007"
|
|
544
|
+
],
|
|
545
|
+
"rwep_score": 45,
|
|
546
|
+
"rwep_factors": {
|
|
547
|
+
"cisa_kev": 0,
|
|
548
|
+
"poc_available": 20,
|
|
549
|
+
"ai_factor": 0,
|
|
550
|
+
"active_exploitation": 20,
|
|
551
|
+
"blast_radius": 30,
|
|
552
|
+
"patch_available": -15,
|
|
553
|
+
"live_patch_available": -10,
|
|
554
|
+
"reboot_required": 0
|
|
555
|
+
},
|
|
556
|
+
"rwep_notes": "RWEP cap of 30 on blast_radius understates the real exposure (42 packages, ~150M+ weekly downloads combined). Operationally treat as P0; the formula caps blast_radius regardless of magnitude. Once CISA KEV-lists this CVE, the +25 boost will lift score to 70 (P1 territory).",
|
|
557
|
+
"epss_score": 0.78,
|
|
558
|
+
"epss_percentile": 0.97,
|
|
559
|
+
"epss_date": "2026-05-13",
|
|
560
|
+
"epss_source": "https://api.first.org/data/v1/epss?cve=CVE-2026-45321",
|
|
561
|
+
"source_verified": "2026-05-13",
|
|
562
|
+
"verification_sources": [
|
|
563
|
+
"https://nvd.nist.gov/vuln/detail/CVE-2026-45321",
|
|
564
|
+
"https://github.com/advisories?query=CVE-2026-45321",
|
|
565
|
+
"https://www.npmjs.com/advisories?search=tanstack"
|
|
566
|
+
],
|
|
567
|
+
"vendor_advisories": [
|
|
568
|
+
{
|
|
569
|
+
"vendor": "TanStack",
|
|
570
|
+
"advisory_id": null,
|
|
571
|
+
"url": "https://github.com/TanStack/query/security/advisories",
|
|
572
|
+
"severity": "critical",
|
|
573
|
+
"published_date": "2026-05-11"
|
|
574
|
+
},
|
|
575
|
+
{
|
|
576
|
+
"vendor": "npm Inc.",
|
|
577
|
+
"advisory_id": null,
|
|
578
|
+
"url": "https://www.npmjs.com/advisories?search=CVE-2026-45321",
|
|
579
|
+
"severity": "critical",
|
|
580
|
+
"published_date": "2026-05-11"
|
|
581
|
+
},
|
|
582
|
+
{
|
|
583
|
+
"vendor": "GitHub Security Advisories",
|
|
584
|
+
"advisory_id": null,
|
|
585
|
+
"url": "https://github.com/advisories?query=CVE-2026-45321",
|
|
586
|
+
"severity": "critical",
|
|
587
|
+
"published_date": "2026-05-11"
|
|
588
|
+
}
|
|
589
|
+
],
|
|
590
|
+
"iocs": {
|
|
591
|
+
"payload_artifacts": [
|
|
592
|
+
"node_modules/@tanstack/*/router_init.js",
|
|
593
|
+
"node_modules/@tanstack/*/router_runtime.js"
|
|
594
|
+
],
|
|
595
|
+
"persistence_artifacts": [
|
|
596
|
+
".claude/settings.json hooks.SessionStart entry running `node .vscode/setup.mjs`",
|
|
597
|
+
".vscode/tasks.json folder-open task pointing at .vscode/setup.mjs",
|
|
598
|
+
"~/Library/LaunchAgents/com.tanstack.*.plist (macOS persistence)",
|
|
599
|
+
"~/.config/systemd/user/*.service referencing the staged setup.mjs (Linux systemd-user persistence)"
|
|
600
|
+
],
|
|
601
|
+
"behavioral": [
|
|
602
|
+
"Build job restores actions/cache key matching Linux-pnpm-store-<hash> written by a non-publishing workflow",
|
|
603
|
+
"Same repo has pull_request_target trigger anywhere AND id-token: write anywhere AND actions/cache used by both",
|
|
604
|
+
"@tanstack/* package resolved within publish window 2026-05-11T19:20Z..2026-05-11T19:26Z"
|
|
605
|
+
],
|
|
606
|
+
"destructive": "Payload triggers wipe on token-revocation — operators rotating npm tokens after suspected exposure should snapshot affected hosts first."
|
|
607
|
+
},
|
|
608
|
+
"last_updated": "2026-05-13"
|
|
495
609
|
}
|
|
496
610
|
}
|
package/data/playbooks/mcp.json
CHANGED
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_meta": {
|
|
3
3
|
"id": "mcp",
|
|
4
|
-
"version": "1.
|
|
5
|
-
"last_threat_review": "2026-05-
|
|
6
|
-
"threat_currency_score":
|
|
4
|
+
"version": "1.1.0",
|
|
5
|
+
"last_threat_review": "2026-05-13",
|
|
6
|
+
"threat_currency_score": 97,
|
|
7
7
|
"changelog": [
|
|
8
|
+
{
|
|
9
|
+
"version": "1.1.0",
|
|
10
|
+
"date": "2026-05-13",
|
|
11
|
+
"summary": "Cross-cuts CVE-2026-45321 (Mini Shai-Hulud TanStack npm worm) on the agent-persistence side. The worm installs SessionStart hooks in .claude/settings.json + folder-open tasks in .vscode/tasks.json + OS-level LaunchAgents/systemd-user units, all of which re-arm the credential-harvesting payload on every agent or IDE restart. Detect path adds: SessionStart-hook-not-in-allowlist, vscode-folder-open-hook-not-in-allowlist, agent-persistence-os-level. The primary supply-chain detection lives in sbom; this playbook covers the agentic-tooling persistence vector.",
|
|
12
|
+
"cves_added": [
|
|
13
|
+
"CVE-2026-45321"
|
|
14
|
+
],
|
|
15
|
+
"framework_gaps_updated": [
|
|
16
|
+
"nist-800-53-AC-2-AI-hook-allowlist",
|
|
17
|
+
"eu-ai-act-art15-agent-persistence"
|
|
18
|
+
]
|
|
19
|
+
},
|
|
8
20
|
{
|
|
9
21
|
"version": "1.0.0",
|
|
10
22
|
"date": "2026-05-11",
|
|
@@ -68,7 +80,8 @@
|
|
|
68
80
|
"T1190"
|
|
69
81
|
],
|
|
70
82
|
"cve_refs": [
|
|
71
|
-
"CVE-2026-30615"
|
|
83
|
+
"CVE-2026-30615",
|
|
84
|
+
"CVE-2026-45321"
|
|
72
85
|
],
|
|
73
86
|
"cwe_refs": [
|
|
74
87
|
"CWE-345",
|