@blamejs/exceptd-skills 0.13.4 → 0.13.5

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.
@@ -0,0 +1,1332 @@
1
+ {
2
+ "_meta": {
3
+ "id": "supply-chain-recovery",
4
+ "version": "1.0.0",
5
+ "last_threat_review": "2026-05-18",
6
+ "threat_currency_score": 96,
7
+ "changelog": [
8
+ {
9
+ "version": "1.0.0",
10
+ "date": "2026-05-18",
11
+ "summary": "Initial seven-phase post-compromise supply-chain recovery playbook. Distinct from `sbom` (pre-incident SBOM hygiene) and `mcp-supply-chain` (MCP tool trust): supply-chain-recovery covers the operator workflow AFTER a maintainer-credential compromise or poisoned-package install — full credential rotation across npm / PyPI / GitHub / cloud / AI-assistant configs, install-window audit (every install since the suspected compromise window), lateral exfil detection on hosts that ran the malicious postinstall, downstream blast-radius enumeration for packages the operator publishes, and provenance-revocation processing through OpenSSF + sigstore + ecosystem advisories. Anchors on MAL-2026-SHAI-HULUD-OSS (TeamPCP open-source release 2026-05-12), MAL-2026-TANSTACK-MINI (42 @tanstack/* packages May 2026), MAL-2026-NODE-IPC-STEALER, the September 2025 + November 2025 + May 2026 Shai-Hulud waves, and the Snowflake credential-leak class. Closes the GRC loop with NIST IR-4 + IR-6 + IR-8 gaps (incident response is undefined for ecosystem-package compromise), ISO A.5.24 + A.5.26 + A.5.27 (incident planning / response / learning), NIS2 Art.21(2)(f) crisis-management gap, DORA Art.17-20 ICT-incident-management gap, EU CRA Art.14 actively-exploited reporting gap, and SOC 2 CC7.4 incident-response gap. Cross-walks to cred-stores (rotation primitive), to idp-incident (when SSO compromise observed), to sbom (downstream consumer notification), to mcp (when AI-assistant configs are exfil targets — Shai-Hulud explicitly reads ~/.cursor, ~/.codeium, ~/.claude). The NEW-CTRL-050 / NEW-CTRL-051 / NEW-CTRL-052 controls from the Shai-Hulud lesson are encoded as remediation paths.",
12
+ "cves_added": [
13
+ "MAL-2026-SHAI-HULUD-OSS",
14
+ "MAL-2026-TANSTACK-MINI",
15
+ "MAL-2026-NODE-IPC-STEALER",
16
+ "CVE-2026-45321"
17
+ ],
18
+ "framework_gaps_updated": [
19
+ "nist-800-53-IR-4-ecosystem-package-compromise",
20
+ "nist-800-53-IR-6-supply-chain-incident-reporting",
21
+ "nist-800-53-IR-8-supply-chain-recovery-plan",
22
+ "iso-27001-2022-A.5.24-supply-chain-incident-planning",
23
+ "iso-27001-2022-A.5.26-supply-chain-response",
24
+ "iso-27001-2022-A.5.27-supply-chain-learning",
25
+ "nis2-art21-2f-crisis-management",
26
+ "dora-art17-20-supply-chain-ict-incident",
27
+ "eu-cra-art14-supply-chain-actively-exploited",
28
+ "soc2-CC7.4-supply-chain-response"
29
+ ]
30
+ }
31
+ ],
32
+ "owner": "@blamejs/platform-security",
33
+ "air_gap_mode": false,
34
+ "scope": "cross-cutting",
35
+ "preconditions": [
36
+ {
37
+ "id": "incident-confirmed",
38
+ "description": "Agent invoked only after a supply-chain compromise is confirmed: a maintainer account is known-compromised, a malicious version has been installed, OR a worm-class indicator (MAL-2026-SHAI-HULUD-OSS family) has fired against operator infrastructure. Pre-incident hygiene playbook is `sbom`, not this one.",
39
+ "check": "supply_chain_incident_confirmed == true",
40
+ "on_fail": "halt"
41
+ },
42
+ {
43
+ "id": "credential-rotation-authority",
44
+ "description": "Agent must have (or hold attestation of) authority to rotate maintainer credentials across npm + PyPI + GitHub + cloud + AI-assistant config stores. Without this, the playbook cannot complete the rotation primitive that closes the compromise window.",
45
+ "check": "operator_holds_rotation_authority == true",
46
+ "on_fail": "halt"
47
+ },
48
+ {
49
+ "id": "install-history-readable",
50
+ "description": "Agent must be able to read npm install history (package-lock.json + .npmrc + ~/.npm/_logs), PyPI install history (pip freeze + pip cache + pipenv logs), and host process / network audit for the suspected compromise window. Without this, the install-window audit cannot bound the affected population.",
51
+ "check": "agent_has_filesystem_read == true",
52
+ "on_fail": "halt"
53
+ }
54
+ ],
55
+ "mutex": [],
56
+ "feeds_into": [
57
+ {
58
+ "playbook_id": "cred-stores",
59
+ "condition": "finding.includes_credential_exposure == true"
60
+ },
61
+ {
62
+ "playbook_id": "idp-incident",
63
+ "condition": "finding.includes_sso_compromise == true"
64
+ },
65
+ {
66
+ "playbook_id": "sbom",
67
+ "condition": "finding.operator_publishes_packages == true"
68
+ },
69
+ {
70
+ "playbook_id": "mcp",
71
+ "condition": "finding.includes_ai_assistant_config_exfil == true"
72
+ },
73
+ {
74
+ "playbook_id": "framework",
75
+ "condition": "analyze.compliance_theater_check.verdict == 'theater'"
76
+ }
77
+ ]
78
+ },
79
+ "domain": {
80
+ "name": "Post-compromise supply-chain recovery",
81
+ "attack_class": "supply-chain",
82
+ "atlas_refs": [
83
+ "AML.T0010",
84
+ "AML.T0016"
85
+ ],
86
+ "attack_refs": [
87
+ "T1195.002",
88
+ "T1199",
89
+ "T1078.004",
90
+ "T1059",
91
+ "T1552.001",
92
+ "T1552.004",
93
+ "T1098",
94
+ "T1539",
95
+ "T1567"
96
+ ],
97
+ "cve_refs": [
98
+ "CVE-2026-45321"
99
+ ],
100
+ "cwe_refs": [
101
+ "CWE-94",
102
+ "CWE-200",
103
+ "CWE-256",
104
+ "CWE-269",
105
+ "CWE-287",
106
+ "CWE-345",
107
+ "CWE-522",
108
+ "CWE-798"
109
+ ],
110
+ "d3fend_refs": [
111
+ "D3-CA",
112
+ "D3-EAL",
113
+ "D3-EI",
114
+ "D3-IOPR",
115
+ "D3-FCR"
116
+ ],
117
+ "frameworks_in_scope": [
118
+ "nist-800-53",
119
+ "nist-csf-2",
120
+ "iso-27001-2022",
121
+ "soc2",
122
+ "nis2",
123
+ "dora",
124
+ "eu-cra",
125
+ "uk-caf",
126
+ "au-ism",
127
+ "cmmc"
128
+ ]
129
+ },
130
+ "phases": {
131
+ "govern": {
132
+ "jurisdiction_obligations": [
133
+ {
134
+ "jurisdiction": "EU",
135
+ "regulation": "NIS2 Art.23",
136
+ "obligation": "notify_regulator",
137
+ "window_hours": 24,
138
+ "clock_starts": "detect_confirmed",
139
+ "evidence_required": [
140
+ "compromised_maintainer_account_inventory",
141
+ "affected_install_window_estimate",
142
+ "downstream_blast_radius_estimate",
143
+ "containment_record"
144
+ ]
145
+ },
146
+ {
147
+ "jurisdiction": "EU",
148
+ "regulation": "DORA Art.19",
149
+ "obligation": "notify_regulator",
150
+ "window_hours": 4,
151
+ "clock_starts": "detect_confirmed",
152
+ "evidence_required": [
153
+ "ict_critical_function_impact",
154
+ "ict_third_party_dependencies_affected",
155
+ "containment_record"
156
+ ]
157
+ },
158
+ {
159
+ "jurisdiction": "EU",
160
+ "regulation": "EU CRA Art.14",
161
+ "obligation": "notify_regulator",
162
+ "window_hours": 24,
163
+ "clock_starts": "detect_confirmed",
164
+ "evidence_required": [
165
+ "actively_exploited_assessment",
166
+ "user_notification_draft",
167
+ "affected_product_inventory"
168
+ ]
169
+ },
170
+ {
171
+ "jurisdiction": "EU",
172
+ "regulation": "GDPR Art.33",
173
+ "obligation": "notify_regulator",
174
+ "window_hours": 72,
175
+ "clock_starts": "detect_confirmed",
176
+ "evidence_required": [
177
+ "data_subject_impact_assessment",
178
+ "exfiltration_window_estimate"
179
+ ]
180
+ },
181
+ {
182
+ "jurisdiction": "US-Federal",
183
+ "regulation": "SEC Item 1.05 (8-K)",
184
+ "obligation": "notify_regulator",
185
+ "window_hours": 96,
186
+ "clock_starts": "analyze_complete",
187
+ "evidence_required": [
188
+ "material_impact_determination",
189
+ "incident_description"
190
+ ]
191
+ },
192
+ {
193
+ "jurisdiction": "US-NY",
194
+ "regulation": "NYDFS 23 NYCRR 500.17",
195
+ "obligation": "notify_regulator",
196
+ "window_hours": 72,
197
+ "clock_starts": "detect_confirmed",
198
+ "evidence_required": [
199
+ "callback_log_excerpt",
200
+ "containment_record"
201
+ ]
202
+ },
203
+ {
204
+ "jurisdiction": "AU",
205
+ "regulation": "APRA CPS 234",
206
+ "obligation": "notify_regulator",
207
+ "window_hours": 72,
208
+ "clock_starts": "validate_complete",
209
+ "evidence_required": [
210
+ "materiality_assessment",
211
+ "remediation_completed_evidence"
212
+ ]
213
+ },
214
+ {
215
+ "jurisdiction": "UK",
216
+ "regulation": "NCSC CAF B5 + ICO Art.33",
217
+ "obligation": "notify_regulator",
218
+ "window_hours": 72,
219
+ "clock_starts": "detect_confirmed",
220
+ "evidence_required": [
221
+ "incident_assessment",
222
+ "containment_record"
223
+ ]
224
+ }
225
+ ],
226
+ "theater_fingerprints": [
227
+ {
228
+ "pattern_id": "slsa-l3-as-compromise-immunity",
229
+ "claim": "We require SLSA L3 provenance on every dependency, so a compromised upstream cannot reach us.",
230
+ "fast_detection_test": "Read the SLSA provenance attestation for a sample of installed packages. SLSA L3 attests that the build was reproducible from a tamper-evident source — it does NOT attest that the source itself is benign. A maintainer-credential compromise where the attacker pushes malicious code through the legitimate signing key produces SLSA-L3-valid provenance for a malicious package. Verification: a fully L3-conformant package that runs malicious postinstall against the operator's host is not a theoretical case — Shai-Hulud 2.0 family attacks include this exact pattern.",
231
+ "implicated_controls": [
232
+ "slsa-l3-build-platform",
233
+ "nist-800-53-SR-3",
234
+ "iso-27001-2022-A.5.21"
235
+ ]
236
+ },
237
+ {
238
+ "pattern_id": "maintainer-credential-rotation-as-recovery",
239
+ "claim": "We rotated the compromised maintainer's npm token, so the incident is closed.",
240
+ "fast_detection_test": "Rotation closes the FUTURE-publish window. It does NOT close the past-install window. Every host that ran `npm install` on a compromised version during the window between malicious-publish and rotation has executed the postinstall payload. Recovery is incomplete without (a) install-window audit on every host, (b) lateral-credential rotation for every credential the postinstall could have exfil'd (cloud SDK creds, GITHUB_TOKEN, .ssh/, ~/.aws, ~/.config/gcloud, ~/.kube, ~/.cursor, ~/.codeium, ~/.claude, ~/.npmrc), (c) downstream-consumer notification if the operator's own packages republished the compromised dependency."
241
+ },
242
+ {
243
+ "pattern_id": "npm-audit-fix-as-resolution",
244
+ "claim": "We ran `npm audit fix` after the compromise and CI passed, so we are clean.",
245
+ "fast_detection_test": "`npm audit fix` upgrades to a non-vulnerable version. It does NOT clean a host whose previous install ran the postinstall payload. It does NOT detect lateral exfil that happened during the compromise window. It does NOT rotate the credentials that were exfil'd. The compromise model is: malicious code RAN on the host; npm audit fix only changes what RUNS NEXT TIME. Real recovery requires forensic-grade host audit + credential rotation + provenance re-establishment."
246
+ },
247
+ {
248
+ "pattern_id": "sbom-as-compromise-detector",
249
+ "claim": "Our SBOM scanner caught the compromised version and blocked the install, so the worm is contained.",
250
+ "fast_detection_test": "SBOM scanners catch named-CVE compromises with a lag — typically minutes to days after MAL-* publication. For wormable supply-chain attacks (Shai-Hulud, Mini Shai-Hulud, TanStack-mini) the malicious version is in the wild for hours before SBOM scanners catch it. Verify: pull the SBOM scanner's hit timestamp against the malicious-version publish timestamp. If the gap is > 0 and the operator's CI ran during the gap, at least one CI host executed the postinstall and the install-window audit is required regardless."
251
+ },
252
+ {
253
+ "pattern_id": "private-registry-mirror-as-shield",
254
+ "claim": "We pull everything from a private registry mirror, so npm registry compromises don't reach us.",
255
+ "fast_detection_test": "Check the mirror's sync cadence. Most private mirrors sync at hourly or sub-hourly cadence from the upstream registry — a compromised version is mirrored automatically within the sync window. The mirror provides version-pinning + cache durability but NOT a content-trust layer. Mirror + manual approval gates between upstream and developer-reachable mirror would close the gap; most mirrors don't have approval gates. Read the mirror config + recent sync log."
256
+ }
257
+ ],
258
+ "framework_context": {
259
+ "gap_summary": "Incident-response frameworks do not contemplate the ecosystem-package-compromise class. NIST 800-53 IR-4 (Incident Handling) + IR-6 (Incident Reporting) + IR-8 (Incident Response Plan) define handling for organisation-owned incidents — the operator's host, the operator's network, the operator's identity plane. A compromise that arrives via the package ecosystem (npm install runs malicious postinstall, exfil'd creds appear in attacker's collector, downstream-consumer installs poisoned operator package) falls between IR's framing of 'incident' and SR's framing of 'supply chain' — neither owns the recovery primitive. ISO 27001 A.5.24 (Information security incident management planning and preparation) + A.5.26 (Response to information security incidents) + A.5.27 (Learning from information security incidents) similarly frame incidents as operator-owned events. NIS2 Art.21(2)(f) names crisis management without specifying supply-chain-recovery workflows. DORA Art.17-20 covers ICT-incident management with classification thresholds anchored on operator-side impact, not on upstream-source compromise. EU CRA Art.14 covers manufacturer disclosure of actively-exploited vulnerabilities — when the manufacturer IS the operator (the operator publishes a package), Art.14 binds; when the operator is consumer-only, Art.14 doesn't bind the consumer's response. SOC 2 CC7.4 (Incident response) inherits the same operator-incident framing. The result: an organisation can be fully NIST/ISO/NIS2/DORA/SOC 2 compliant for incident response while having NO documented procedure for the maintainer-credential-rotation + install-window-audit + AI-assistant-config-rotation + downstream-consumer-notification quadruple that recovery requires.",
260
+ "lag_score": 270,
261
+ "per_framework_gaps": [
262
+ {
263
+ "framework": "nist-800-53",
264
+ "control_id": "IR-4 — Incident Handling",
265
+ "designed_for": "Handling of detected security incidents through preparation, detection, containment, eradication, recovery, and lessons-learned phases.",
266
+ "insufficient_because": "IR-4 framing assumes the incident is operator-owned (operator host, operator network, operator identity). An ecosystem-package compromise where the malicious code runs on developer + CI hosts via package-manager-mediated install does not have a documented IR-4 sub-procedure for: maintainer-credential rotation, install-window audit, AI-assistant config exfil scope, downstream-consumer notification."
267
+ },
268
+ {
269
+ "framework": "nist-800-53",
270
+ "control_id": "IR-6 — Incident Reporting",
271
+ "designed_for": "Reporting incidents to internal + external parties.",
272
+ "insufficient_because": "External-reporting language assumes regulator + law-enforcement + affected-individual. For ecosystem-package compromise, the affected population includes every downstream consumer of operator-published packages — IR-6 does not name this audience as a reporting target, leaving the OpenSSF MAL feed / npm-advisory / GHSA pipeline outside the operator's documented reporting workflow."
273
+ },
274
+ {
275
+ "framework": "nist-800-53",
276
+ "control_id": "IR-8 — Incident Response Plan",
277
+ "designed_for": "Documented IR plan covering all reasonable incident types.",
278
+ "insufficient_because": "Plans typically cover ransomware, DDoS, insider, account-compromise, data-breach. Supply-chain-recovery is rarely a named scenario; when present, it usually omits AI-assistant-config-exfil scope (the Shai-Hulud-class explicit exfil targets ~/.cursor, ~/.codeium, ~/.claude)."
279
+ },
280
+ {
281
+ "framework": "nist-800-53",
282
+ "control_id": "SR-3 — Supply Chain Controls and Processes",
283
+ "designed_for": "Supply-chain risk management.",
284
+ "insufficient_because": "Pre-incident framing. SR-3 does not own post-incident recovery. The bridge from SR-3 (we manage supply-chain risk) to IR-4 (we handle incidents) for the ecosystem-package class is undefined."
285
+ },
286
+ {
287
+ "framework": "iso-27001-2022",
288
+ "control_id": "A.5.24 — Information security incident management planning and preparation",
289
+ "designed_for": "Documented incident-management process + responsibilities + playbooks.",
290
+ "insufficient_because": "Same operator-owned incident framing as NIST IR-4. Ecosystem-package compromise does not have a documented sub-process in standard A.5.24 implementations."
291
+ },
292
+ {
293
+ "framework": "iso-27001-2022",
294
+ "control_id": "A.5.26 — Response to information security incidents",
295
+ "designed_for": "Response workflows for confirmed incidents.",
296
+ "insufficient_because": "Response workflows assume operator-side mitigation primitives. Maintainer-credential rotation across multiple ecosystems + cross-ecosystem install-window audit + downstream-consumer notification are not standard A.5.26 response primitives."
297
+ },
298
+ {
299
+ "framework": "iso-27001-2022",
300
+ "control_id": "A.5.27 — Learning from information security incidents",
301
+ "designed_for": "Post-incident learning and control improvement.",
302
+ "insufficient_because": "Learning workflows assume operator-internal lessons. Cross-ecosystem learnings (e.g. Shai-Hulud-class AI-assistant-config exfil) require cross-org sharing not anchored in A.5.27."
303
+ },
304
+ {
305
+ "framework": "nis2",
306
+ "control_id": "Art.21(2)(f) — Crisis management",
307
+ "designed_for": "Crisis-management measures as essential cybersecurity measure.",
308
+ "insufficient_because": "Names crisis management without specifying supply-chain-recovery workflows. Essential-entity crisis plans typically omit ecosystem-package compromise as a scenario; when present, recovery primitives are under-specified."
309
+ },
310
+ {
311
+ "framework": "dora",
312
+ "control_id": "Art.17-20 — ICT-related incident management",
313
+ "designed_for": "Financial-entity ICT incident classification + management + reporting.",
314
+ "insufficient_because": "Classification thresholds anchor on operator-side impact (clients affected, services unavailable, data lost). Upstream-source-compromise impact propagates through dependency tree before manifesting as operator-side impact — DORA classification can miss the early-detection window."
315
+ },
316
+ {
317
+ "framework": "eu-cra",
318
+ "control_id": "Art.14 — Coordinated vulnerability disclosure / actively-exploited reporting",
319
+ "designed_for": "Manufacturer obligation to disclose actively-exploited vulnerabilities.",
320
+ "insufficient_because": "Binds the manufacturer (operator who publishes packages). Does not bind the consumer-only operator. For a pure consumer, Art.14 produces inbound disclosure but no recovery primitive."
321
+ },
322
+ {
323
+ "framework": "soc2",
324
+ "control_id": "CC7.4 — Incident response",
325
+ "designed_for": "Trust-services-criteria for incident response.",
326
+ "insufficient_because": "Inherits operator-incident framing. A CC7.4 evidence pack typically does not include ecosystem-package compromise sub-playbooks."
327
+ },
328
+ {
329
+ "framework": "uk-caf",
330
+ "control_id": "D1 — Response and recovery planning",
331
+ "designed_for": "NCSC CAF outcome for incident response + recovery.",
332
+ "insufficient_because": "Outcome-based. Supply-chain-recovery primitives not named as a D1 input. Compliant CAF profile may have no ecosystem-package compromise scenario in the recovery plan."
333
+ }
334
+ ]
335
+ },
336
+ "skill_preload": [
337
+ "supply-chain-integrity",
338
+ "incident-response-playbook",
339
+ "ransomware-response",
340
+ "coordinated-vuln-disclosure",
341
+ "framework-gap-analysis",
342
+ "compliance-theater",
343
+ "policy-exception-gen",
344
+ "exploit-scoring"
345
+ ]
346
+ },
347
+ "direct": {
348
+ "threat_context": "Supply-chain-recovery landscape mid-2026 is dominated by the Shai-Hulud worm family. The September 2025 Shai-Hulud wave (180+ npm packages) established the modular pattern: postinstall harvests local credentials (~/.aws, ~/.config/gcloud, ~/.kube, ~/.ssh, ~/.cursor, ~/.codeium, ~/.claude, ~/.npmrc) and republishes to other packages the host has npm-publish access to. The November 2025 Shai-Hulud 2.0 wave doubled down on AI-assistant config exfil — explicit targets included Claude Code settings, Cursor MCP config, Codeium / Windsurf MCP config, plus startup hooks that re-execute the worm on Claude restart. The May 2026 Mini Shai-Hulud wave (Microsoft Security Research, 2026-05-11) compromised 170+ npm + 2 PyPI packages across 404 malicious versions including the @tanstack/* family (42 packages). TeamPCP open-sourced the complete Shai-Hulud framework to GitHub on 2026-05-12 under MIT license with a $1,000 USD (Monero) bounty contest judged on downstream supply-chain impact. Ox Security observed third-party copycats within hours of release. CVE-2026-45321 is the named worm-via-GitHub-Actions instance — a compromised package's postinstall captures the runner's GITHUB_TOKEN + cloud-OIDC token and uses them to publish more compromised packages from the operator's own pipeline. MAL-2026-NODE-IPC-STEALER extends the pattern to node-ipc-class targeted exfil. The 2024 Snowflake intrusion class remains the canonical credential-leak side: long-lived OIDC / API tokens leaked in CI logs or workstation config files become persistent take-over primitives across cloud, source-control, and AI-assistant planes. The unifying recovery primitive: every credential that EVER lived on a host that ran a compromised postinstall must be considered exfil'd; rotation must be exhaustive across every ecosystem (npm + PyPI + GitHub + cloud + AI-assistant + secret-store). NEW-CTRL-050 (post-compromise maintainer-credential-rotation exhaustiveness), NEW-CTRL-051 (install-window audit across the full ecosystem reach), and NEW-CTRL-052 (AI-assistant config exfil as first-class recovery primitive) emerged from the Shai-Hulud lesson and are encoded in this playbook's remediation paths.",
349
+ "rwep_threshold": {
350
+ "escalate": 95,
351
+ "monitor": 75,
352
+ "close": 35
353
+ },
354
+ "framework_lag_declaration": "NIST 800-53 IR-4 + IR-6 + IR-8 + SR-3, ISO 27001 A.5.24 + A.5.26 + A.5.27, NIS2 Art.21(2)(f), DORA Art.17-20, EU CRA Art.14, SOC 2 CC7.4, UK CAF D1 collectively do not specify the ecosystem-package compromise recovery class. None mandate maintainer-credential rotation across multiple ecosystems, install-window audit, AI-assistant config exfil scope, or downstream-consumer notification as named recovery primitives. The Shai-Hulud family compromises since September 2025 have established the recovery pattern operationally, but no framework has caught up. Lag = ~270 days behind operational pattern establishment. Compensating controls (maintainer credential rotation runbook + install-window audit tooling + AI-assistant config exfil monitoring + downstream-consumer notification process + provenance-revocation runbook) must close the gap before SLA-only compliance can be accepted. None of the frameworks in scope require any of those five recovery primitives.",
355
+ "skill_chain": [
356
+ {
357
+ "skill": "supply-chain-integrity",
358
+ "purpose": "Establish the trust-boundary baseline for the operator's dependency tree + outbound publish surface; identify which ecosystems are in scope.",
359
+ "required": true
360
+ },
361
+ {
362
+ "skill": "incident-response-playbook",
363
+ "purpose": "Anchor the recovery sequence: preparation, detection (already complete by precondition), containment, eradication, recovery, lessons-learned.",
364
+ "required": true
365
+ },
366
+ {
367
+ "skill": "ransomware-response",
368
+ "purpose": "Apply the credential-rotation + lateral-movement audit primitives (these primitives generalise from ransomware to supply-chain recovery; both require exhaustive rotation + multi-host scope).",
369
+ "skip_if": "no_lateral_movement_evidence == true",
370
+ "required": false
371
+ },
372
+ {
373
+ "skill": "coordinated-vuln-disclosure",
374
+ "purpose": "Drive the downstream-consumer notification path: OpenSSF MAL feed, GHSA advisory, npm-advisory, ecosystem-specific advisories.",
375
+ "skip_if": "operator_does_not_publish_packages == true",
376
+ "required": false
377
+ },
378
+ {
379
+ "skill": "exploit-scoring",
380
+ "purpose": "Compute RWEP for the recovery scope: every affected asset × every exfil'd credential class × every downstream consumer.",
381
+ "required": true
382
+ },
383
+ {
384
+ "skill": "framework-gap-analysis",
385
+ "purpose": "Map each recovery primitive against the framework controls that don't require it.",
386
+ "required": true
387
+ },
388
+ {
389
+ "skill": "compliance-theater",
390
+ "purpose": "Run the five theater tests in govern.theater_fingerprints; emit verdict per pattern.",
391
+ "required": true
392
+ },
393
+ {
394
+ "skill": "policy-exception-gen",
395
+ "purpose": "Generate auditor-ready exception language for recovery primitives that cannot be completed within the jurisdiction's window.",
396
+ "skip_if": "close.exception_generation.trigger_condition == false",
397
+ "required": false
398
+ }
399
+ ],
400
+ "token_budget": {
401
+ "estimated_total": 24000,
402
+ "breakdown": {
403
+ "govern": 3000,
404
+ "direct": 1900,
405
+ "look": 2700,
406
+ "detect": 3300,
407
+ "analyze": 5000,
408
+ "validate": 4500,
409
+ "close": 3600
410
+ }
411
+ }
412
+ },
413
+ "look": {
414
+ "artifacts": [
415
+ {
416
+ "id": "compromised-package-inventory",
417
+ "type": "config_file",
418
+ "source": "List the suspected-compromised packages with timestamps: the upstream advisory (OpenSSF MAL, GHSA, npm-advisory, PyPI-advisory) + the operator's own determination via Shai-Hulud-family indicators. Capture per package: name, malicious version(s), publish timestamp, removal/yanking timestamp.",
419
+ "description": "Bounded malicious-version inventory. Every other artefact + indicator scopes against this.",
420
+ "required": true,
421
+ "air_gap_alternative": "Use the operator's locally-cached advisory archive + community ingestion of the OpenSSF MAL feed; mark live advisory state as inventory_gap=advisories_unreachable."
422
+ },
423
+ {
424
+ "id": "install-history-per-host",
425
+ "type": "audit_trail",
426
+ "source": "Per host that may have run `npm install` or `pip install` since the compromise window: read package-lock.json + ~/.npm/_logs/*.log + ~/.npm/_cacache/ + pip freeze + ~/.cache/pip + ~/.local/share/pipenv/. For CI hosts: read GitHub Actions workflow logs + GitLab pipeline logs + BuildKite job logs + CircleCI artefacts. Cross-reference against compromised-package-inventory to surface hits.",
427
+ "description": "Per-host install audit. Lists every install of a compromised version within the window.",
428
+ "required": true,
429
+ "air_gap_alternative": "Local install-log walk only."
430
+ },
431
+ {
432
+ "id": "maintainer-credential-inventory",
433
+ "type": "config_file",
434
+ "source": "List every credential that ever lived on a host that ran a compromised install: npm tokens (~/.npmrc + npm whoami output cache), PyPI tokens (~/.pypirc), GitHub PAT + GitHub Apps installation tokens + GITHUB_TOKEN in CI logs, cloud SDK credentials (~/.aws/credentials, ~/.config/gcloud, ~/.azure, ~/.kube), SSH private keys (~/.ssh/id_*), AI-assistant config tokens (~/.cursor/mcp.json, ~/.codeium/windsurf/mcp_config.json, ~/.claude/settings.json + Claude Code startup hooks), secret-store CLI sessions (gh auth, vault token, doctl, gcloud auth).",
435
+ "description": "Exhaustive credential inventory across every credential class the Shai-Hulud family exfil's. Drives rotation scope.",
436
+ "required": true,
437
+ "air_gap_alternative": "Local host filesystem walk only."
438
+ },
439
+ {
440
+ "id": "outbound-publish-surface",
441
+ "type": "config_file",
442
+ "source": "Per ecosystem: list every package the operator's compromised maintainer credentials have publish authority on. npm: `npm access list packages` per token; PyPI: PyPI account project list; GitHub: repos with `write:packages` for the affected token. Cross-reference against the operator's published-package register.",
443
+ "description": "Downstream blast-radius enumeration. Lists every package the worm could have republished from the operator's credentials.",
444
+ "required": true,
445
+ "air_gap_alternative": "Local published-package register only; mark live publish-authority enumeration as inventory_gap=registry_api_unavailable."
446
+ },
447
+ {
448
+ "id": "lateral-exfil-network-evidence",
449
+ "type": "network_capture",
450
+ "source": "For the compromise window: pull network egress logs from hosts that ran compromised installs. Filter for outbound to Shai-Hulud-family C2 destinations + DNS queries for known worm collector domains + connections to known credential-collector endpoints (TeamPCP's documented C2 + ecosystem-aggregator pastebins). For CI hosts: outbound from runner during the window.",
451
+ "description": "Network-side exfil evidence. Confirms (or refutes) that credentials were actually exfil'd vs just exposed to the postinstall.",
452
+ "required": false,
453
+ "air_gap_alternative": "Local netflow + DNS query log + egress-proxy log retention."
454
+ },
455
+ {
456
+ "id": "ai-assistant-config-snapshot",
457
+ "type": "config_file",
458
+ "source": "Per host with AI-assistant installs: snapshot ~/.cursor/mcp.json, ~/.codeium/windsurf/mcp_config.json, ~/.claude/settings.json + ~/.claude/projects/* + Claude Code startup hooks (~/.claude/hooks/, ~/.bashrc / ~/.zshrc for Claude Code invocations). Compute SHA of each file; compare against pre-compromise baseline if available.",
459
+ "description": "AI-assistant config state. Shai-Hulud-family attacks add startup hooks that persist worm execution into the AI assistant — config snapshot detects the persistence.",
460
+ "required": true,
461
+ "air_gap_alternative": "Local filesystem walk."
462
+ },
463
+ {
464
+ "id": "downstream-consumer-list",
465
+ "type": "config_file",
466
+ "source": "For each operator-published package in outbound-publish-surface: enumerate downstream consumers via npm (`npm view <pkg> dependents`, libraries.io API, deps.dev API), PyPI (libraries.io), GitHub (dependents tab via gh api). Capture consumer count + sample of high-reach consumers.",
467
+ "description": "Downstream-consumer audience for the notification path. Drives advisory cadence.",
468
+ "required": false,
469
+ "air_gap_alternative": "Locally cached dependents enumeration; mark live consumer enumeration as inventory_gap=consumer_api_unavailable."
470
+ },
471
+ {
472
+ "id": "provenance-revocation-state",
473
+ "type": "config_file",
474
+ "source": "Per affected package: check sigstore + npm provenance + GHSA + OSV for revocation entries; check ecosystem-specific yanking state (npm: `npm view <pkg>@<ver> deprecated`, PyPI: yanked field). Capture per malicious version: revoked? deprecated? yanked? withdrawn?",
475
+ "description": "Provenance / yanking state across the affected package set. Drives the operator's downstream-consumer-aiding revocation steps.",
476
+ "required": false,
477
+ "air_gap_alternative": "Local cached provenance state + ecosystem advisory archive."
478
+ },
479
+ {
480
+ "id": "incident-response-plan",
481
+ "type": "config_file",
482
+ "source": "Read the operator's IR plan + IR runbook. Confirm ecosystem-package compromise is named, recovery primitives are documented, AI-assistant config exfil is named.",
483
+ "description": "Operator's pre-existing IR plan. Used to detect framework-coverage gap.",
484
+ "required": true,
485
+ "air_gap_alternative": "Local IR plan filesystem walk."
486
+ }
487
+ ],
488
+ "collection_scope": {
489
+ "time_window": "compromise_window_plus_safety_margin",
490
+ "asset_scope": "every_host_that_ran_npm_or_pip_install_during_window_plus_operator_published_package_consumer_set",
491
+ "depth": "deep",
492
+ "sampling": "complete coverage of install history + maintainer credential inventory + AI-assistant config snapshot. Network-evidence + downstream-consumer enumeration sampled where complete collection is infeasible. Re-collect on every new advisory in the compromise family."
493
+ },
494
+ "environment_assumptions": [
495
+ {
496
+ "assumption": "operator has authority to rotate maintainer credentials across npm + PyPI + GitHub + cloud + AI-assistant + secret stores",
497
+ "if_false": "Halt with authorisation_required — recovery cannot complete without rotation primitive."
498
+ },
499
+ {
500
+ "assumption": "install-history is captured (package-lock.json, npm logs, pip cache, CI logs retained past the window)",
501
+ "if_false": "Install-window audit cannot bound the affected population. Mark install-history-per-host as inventory_gap=install_logs_pruned and treat every host with any install activity in the window as suspect."
502
+ },
503
+ {
504
+ "assumption": "AI-assistant config files are present and readable",
505
+ "if_false": "Cannot detect Shai-Hulud-family startup-hook persistence. Mark ai-assistant-config-snapshot as inventory_gap=ai_configs_absent; escalate every host that has AI-assistant installs as suspect-persistence."
506
+ },
507
+ {
508
+ "assumption": "downstream-consumer enumeration APIs reachable OR cached",
509
+ "if_false": "Mark downstream-consumer-list as inventory_gap=consumer_enumeration_unavailable; default the consumer notification to the broadest reasonable audience."
510
+ }
511
+ ],
512
+ "fallback_if_unavailable": [
513
+ {
514
+ "artifact_id": "compromised-package-inventory",
515
+ "fallback_action": "escalate_to_human",
516
+ "confidence_impact": "high"
517
+ },
518
+ {
519
+ "artifact_id": "install-history-per-host",
520
+ "fallback_action": "use_compensating_artifact",
521
+ "confidence_impact": "high"
522
+ },
523
+ {
524
+ "artifact_id": "maintainer-credential-inventory",
525
+ "fallback_action": "escalate_to_human",
526
+ "confidence_impact": "high"
527
+ },
528
+ {
529
+ "artifact_id": "outbound-publish-surface",
530
+ "fallback_action": "use_compensating_artifact",
531
+ "confidence_impact": "high"
532
+ },
533
+ {
534
+ "artifact_id": "lateral-exfil-network-evidence",
535
+ "fallback_action": "mark_inconclusive",
536
+ "confidence_impact": "medium"
537
+ },
538
+ {
539
+ "artifact_id": "ai-assistant-config-snapshot",
540
+ "fallback_action": "escalate_to_human",
541
+ "confidence_impact": "high"
542
+ },
543
+ {
544
+ "artifact_id": "downstream-consumer-list",
545
+ "fallback_action": "use_compensating_artifact",
546
+ "confidence_impact": "medium"
547
+ },
548
+ {
549
+ "artifact_id": "incident-response-plan",
550
+ "fallback_action": "mark_inconclusive",
551
+ "confidence_impact": "low"
552
+ }
553
+ ]
554
+ },
555
+ "detect": {
556
+ "indicators": [
557
+ {
558
+ "id": "compromised-install-on-host",
559
+ "type": "log_pattern",
560
+ "value": "Cross-join compromised-package-inventory × install-history-per-host: any host has an install record for a compromised version within the publish-to-rotation window.",
561
+ "description": "Host ran a compromised postinstall. Primary recovery scope indicator.",
562
+ "confidence": "deterministic",
563
+ "deterministic": true,
564
+ "attack_ref": "T1195.002",
565
+ "cve_ref": "MAL-2026-SHAI-HULUD-OSS",
566
+ "false_positive_checks_required": [
567
+ "Confirm the install actually executed lifecycle scripts. `npm install --ignore-scripts` or PyPI `--no-deps` runs the install but does not execute postinstall. Read the npm log for the postinstall line; absence demotes severity.",
568
+ "Confirm the host wasn't isolated (no outbound network, no credential mounting) during the install. A throwaway container with no credentials is lower-blast-radius than a developer workstation.",
569
+ "Confirm the install isn't a downgrade-and-test against an isolated reproduction environment. Researcher / red-team reproduction is not a recovery trigger."
570
+ ]
571
+ },
572
+ {
573
+ "id": "ai-assistant-config-mutated",
574
+ "type": "file_hash",
575
+ "value": "Within the ai-assistant-config-snapshot artefact: ~/.claude/settings.json OR ~/.cursor/mcp.json OR ~/.codeium/windsurf/mcp_config.json OR Claude Code startup hook files have SHA mismatch against pre-compromise baseline; OR baseline absent AND files contain references to non-allowlisted MCP servers / startup commands invoking shell-out to non-allowlisted binaries.",
576
+ "description": "AI-assistant config mutated — Shai-Hulud-family persistence pattern. Worm re-executes on next AI-assistant invocation.",
577
+ "confidence": "deterministic",
578
+ "deterministic": true,
579
+ "attack_ref": "T1098",
580
+ "cve_ref": "MAL-2026-SHAI-HULUD-OSS",
581
+ "false_positive_checks_required": [
582
+ "Confirm the mutation is not the operator's own intentional config edit (recent legitimate add of an MCP server, hook update). Check timestamp against the operator's change record.",
583
+ "Confirm the mutation actually invokes a non-allowlisted binary or unexpected MCP server. Allowlisted org-internal MCP servers / hooks are not findings even when added recently."
584
+ ]
585
+ },
586
+ {
587
+ "id": "credential-store-touched-during-window",
588
+ "type": "log_pattern",
589
+ "value": "Per host that ran a compromised install: read access timestamps + audit logs for ~/.aws/credentials, ~/.config/gcloud, ~/.kube, ~/.ssh, ~/.npmrc, ~/.pypirc, ~/.cursor, ~/.codeium, ~/.claude. Any access within 5 minutes of a compromised postinstall execution timestamp is a positive hit.",
590
+ "description": "Credential-store read access during compromise window = exfil-plausible. Drives rotation scope.",
591
+ "confidence": "high",
592
+ "deterministic": false,
593
+ "attack_ref": "T1552.001",
594
+ "false_positive_checks_required": [
595
+ "Confirm the access wasn't an operator-driven action concurrent with the install (e.g. operator runs `aws sts get-caller-identity` for an unrelated reason at the same moment). Cross-reference shell history + operator's stated actions.",
596
+ "Confirm the access wasn't a legitimate side effect of the npm/pip toolchain itself (e.g. npm reads ~/.npmrc to determine registry URL on every install). Distinguish toolchain reads from postinstall-script reads where possible."
597
+ ]
598
+ },
599
+ {
600
+ "id": "outbound-exfil-during-window",
601
+ "type": "network_pattern",
602
+ "value": "Within lateral-exfil-network-evidence: host that ran a compromised install made outbound connections during the install window to (a) IPs/domains documented as Shai-Hulud-family C2, (b) pastebin / paste-rs / gist (anonymous-paste services), (c) Discord/Slack/Telegram webhook endpoints not in operator allowlist, (d) attacker-controlled GitHub gists or repos.",
603
+ "description": "Confirmed exfil — credentials are gone, not just exposed.",
604
+ "confidence": "deterministic",
605
+ "deterministic": true,
606
+ "attack_ref": "T1567",
607
+ "false_positive_checks_required": [
608
+ "Confirm the destination isn't on the operator's legitimate dependency / telemetry allowlist. The operator's own error-tracker, observability provider, or build-cache mirror is not exfil.",
609
+ "Confirm the outbound traffic isn't a side effect of the package's legitimate functionality. Some packages legitimately call out (telemetry, version-check). Distinguish destination patterns against the package's documented network footprint."
610
+ ]
611
+ },
612
+ {
613
+ "id": "operator-published-package-republish",
614
+ "type": "log_pattern",
615
+ "value": "Within outbound-publish-surface × ecosystem-publish-log (npm publish log, PyPI upload history, GitHub Packages publish event): the operator's package has a version published during the compromise window that the operator's release process does NOT correspond to (no matching CI run, no maintainer-acknowledged push).",
616
+ "description": "Operator's own package was republished by the worm. Downstream-consumer notification is now mandatory; Art.14 binds the operator as manufacturer.",
617
+ "confidence": "deterministic",
618
+ "deterministic": true,
619
+ "attack_ref": "T1195.002",
620
+ "cve_ref": "MAL-2026-SHAI-HULUD-OSS",
621
+ "false_positive_checks_required": [
622
+ "Confirm the publish isn't from a legitimate maintainer not in the standard CI release process (some teams have manual publish from one maintainer's workstation). Cross-reference the publish-user identity + the maintainer's stated activity.",
623
+ "Confirm the publish version is non-deprecated. A republish followed by immediate yanking by the maintainer themselves is part of recovery, not the compromise."
624
+ ]
625
+ },
626
+ {
627
+ "id": "ir-plan-missing-supply-chain-recovery",
628
+ "type": "log_pattern",
629
+ "value": "Within incident-response-plan: no named scenario for ecosystem-package compromise OR recovery primitives (maintainer-credential rotation, install-window audit, AI-assistant config exfil scope, downstream-consumer notification) are absent.",
630
+ "description": "Operator's IR plan does not contemplate this incident class. Recovery proceeds ad-hoc — high risk of incomplete primitives.",
631
+ "confidence": "deterministic",
632
+ "deterministic": true,
633
+ "false_positive_checks_required": [
634
+ "Confirm the missing primitive isn't documented in a separate runbook (e.g. a 'supply-chain incident runbook' standalone). Search for the primitive across the runbook archive before concluding absence.",
635
+ "Confirm the plan's named scenarios don't generalise to ecosystem-package compromise (e.g. a 'malicious code execution' scenario that covers the recovery primitives even if not labelled 'supply-chain'). Read the scenario contents, not just the title."
636
+ ]
637
+ },
638
+ {
639
+ "id": "long-lived-token-in-compromised-ci-log",
640
+ "type": "log_pattern",
641
+ "value": "Within install-history-per-host (CI subset) × maintainer-credential-inventory: a long-lived token (OAuth refresh, GitHub Apps installation, npm token, PyPI token, cloud STS session token) appears in a CI log artefact retained > 7 days AND the log corresponds to a job that ran a compromised install.",
642
+ "description": "Snowflake-class pattern compounded with worm: token in long-retained CI log was reachable by the postinstall.",
643
+ "confidence": "high",
644
+ "deterministic": false,
645
+ "attack_ref": "T1552.004"
646
+ },
647
+ {
648
+ "id": "no-provenance-revocation-filed",
649
+ "type": "behavioral_signal",
650
+ "value": "Within provenance-revocation-state: for operator-published packages that were republished by the worm (operator-published-package-republish == fired): no advisory has been filed on OpenSSF MAL / GHSA / npm-advisory / PyPI-advisory naming the affected version.",
651
+ "description": "Downstream consumers still install the compromised version because no provenance-revocation advisory exists.",
652
+ "confidence": "deterministic",
653
+ "deterministic": true,
654
+ "false_positive_checks_required": [
655
+ "Confirm the advisory hasn't been filed under a different identifier (vendor-specific advisory ID, organisation-internal CVE). Search the OpenSSF MAL feed + GHSA + ecosystem-specific advisory archives by the package name + version.",
656
+ "If the affected version has been yanked from the registry, the immediate risk is mitigated even without an advisory — but the advisory is still required for retrospective consumer notification."
657
+ ]
658
+ }
659
+ ],
660
+ "false_positive_profile": [
661
+ {
662
+ "indicator_id": "compromised-install-on-host",
663
+ "benign_pattern": "Throwaway container in CI that doesn't mount any credentials and is destroyed at end of job.",
664
+ "distinguishing_test": "Confirm the container has no credentials mounted (no /run/secrets, no env vars containing tokens, no .npmrc with token, no AWS_* env vars) AND the container's network egress is restricted. If all three hold, demote to monitor — the postinstall ran but had nothing to exfil and nowhere to send it."
665
+ },
666
+ {
667
+ "indicator_id": "ai-assistant-config-mutated",
668
+ "benign_pattern": "Operator legitimately added an MCP server config or modified Claude Code settings during a non-compromise activity.",
669
+ "distinguishing_test": "Cross-reference the mutation timestamp against operator's stated activity log. Confirm the new MCP server or hook is on the org's allowlist. If both conditions hold, demote."
670
+ }
671
+ ],
672
+ "minimum_signal": {
673
+ "detected": "At least one of {compromised-install-on-host, ai-assistant-config-mutated, outbound-exfil-during-window, operator-published-package-republish} fires — recovery scope established.",
674
+ "inconclusive": "Compromised-package-inventory exists but install-history-per-host or maintainer-credential-inventory cannot be reconciled (logs pruned, credential stores inaccessible). Cannot bound recovery scope.",
675
+ "not_detected": "Compromised-package-inventory has 0 hits against install-history-per-host, AI-assistant configs match baseline, no credential-store read access during the window, no outbound exfil, no operator-published-package republish."
676
+ }
677
+ },
678
+ "analyze": {
679
+ "rwep_inputs": [
680
+ {
681
+ "signal_id": "compromised-install-on-host",
682
+ "rwep_factor": "active_exploitation",
683
+ "weight": 20,
684
+ "notes": "Wormable supply-chain compromise — confirmed in-the-wild exploitation across the Shai-Hulud family."
685
+ },
686
+ {
687
+ "signal_id": "compromised-install-on-host",
688
+ "rwep_factor": "blast_radius",
689
+ "weight": 25,
690
+ "notes": "Per-host blast radius scales with credential surface + outbound network reach."
691
+ },
692
+ {
693
+ "signal_id": "ai-assistant-config-mutated",
694
+ "rwep_factor": "ai_weaponization",
695
+ "weight": 15,
696
+ "notes": "AI-assistant persistence pattern — the operator's own AI assistant becomes a re-execution vector."
697
+ },
698
+ {
699
+ "signal_id": "ai-assistant-config-mutated",
700
+ "rwep_factor": "active_exploitation",
701
+ "weight": 20,
702
+ "notes": "Shai-Hulud family operationally targets AI-assistant configs."
703
+ },
704
+ {
705
+ "signal_id": "outbound-exfil-during-window",
706
+ "rwep_factor": "active_exploitation",
707
+ "weight": 20,
708
+ "notes": "Confirmed exfil — credentials reachable to attacker collector."
709
+ },
710
+ {
711
+ "signal_id": "outbound-exfil-during-window",
712
+ "rwep_factor": "blast_radius",
713
+ "weight": 25,
714
+ "notes": "Blast radius spans every credential reachable from the exfil host."
715
+ },
716
+ {
717
+ "signal_id": "operator-published-package-republish",
718
+ "rwep_factor": "active_exploitation",
719
+ "weight": 20,
720
+ "notes": "Worm has propagated through operator's publish surface — downstream consumers actively at risk."
721
+ },
722
+ {
723
+ "signal_id": "operator-published-package-republish",
724
+ "rwep_factor": "blast_radius",
725
+ "weight": 25,
726
+ "notes": "Downstream blast radius = every consumer of the operator's package set."
727
+ },
728
+ {
729
+ "signal_id": "long-lived-token-in-compromised-ci-log",
730
+ "rwep_factor": "cisa_kev",
731
+ "weight": 25,
732
+ "notes": "Snowflake-class is on CISA KEV in operational form (CVE-2024-1709 included)."
733
+ },
734
+ {
735
+ "signal_id": "no-provenance-revocation-filed",
736
+ "rwep_factor": "ai_weaponization",
737
+ "weight": 5,
738
+ "notes": "Absence of advisory amplifies downstream-consumer compromise window."
739
+ },
740
+ {
741
+ "signal_id": "ir-plan-missing-supply-chain-recovery",
742
+ "rwep_factor": "patch_available",
743
+ "weight": -5,
744
+ "notes": "Plan-gap is a programme-level issue; modest mitigation via ad-hoc execution."
745
+ }
746
+ ],
747
+ "blast_radius_model": {
748
+ "scope_question": "If a supply-chain compromise is incompletely recovered, what scope of downstream compromise does the operator's residual exposure deliver to attacker C2 + downstream consumer + AI-assistant re-execution paths?",
749
+ "scoring_rubric": [
750
+ {
751
+ "condition": "Single host ran compromised install in throwaway container with no credentials + no network egress + no AI assistant.",
752
+ "blast_radius_score": 1,
753
+ "description": "Postinstall ran but had nothing to exfil + nowhere to send it. Recovery = destroy container, rotate any unused-but-present tokens out of caution."
754
+ },
755
+ {
756
+ "condition": "Developer workstation with personal git creds + npm token + AWS dev credentials.",
757
+ "blast_radius_score": 2,
758
+ "description": "Personal credential exfil. Recovery = rotate developer creds, audit any commits / publishes from the workstation since compromise."
759
+ },
760
+ {
761
+ "condition": "CI runner host with org GITHUB_TOKEN + cloud STS session + npm publish token for one operator package.",
762
+ "blast_radius_score": 3,
763
+ "description": "Org-scoped credential exfil. Recovery = rotate every CI-scoped token, audit publishes during window."
764
+ },
765
+ {
766
+ "condition": "Multiple CI hosts with publish rights across multiple operator packages + AI-assistant configs on developer workstations.",
767
+ "blast_radius_score": 4,
768
+ "description": "Multi-asset publish surface compromise + AI-assistant persistence — downstream-consumer notification required, AI-assistant re-execution scope to clean."
769
+ },
770
+ {
771
+ "condition": "Compromise reached identity-plane (SSO admin token exfil, org-admin GitHub Apps installation token, cloud-org-admin STS), OR operator's published packages already republished by worm AND no advisory yet filed.",
772
+ "blast_radius_score": 5,
773
+ "description": "Full identity-plane / supply-chain propagation. Org-wide rotation + downstream-consumer notification + Art.14 manufacturer disclosure required."
774
+ }
775
+ ]
776
+ },
777
+ "compliance_theater_check": {
778
+ "claim": "Incident response is operating per NIST IR-4 + IR-6 + IR-8, ISO A.5.24 + A.5.26 + A.5.27, NIS2 Art.21(2)(f), DORA Art.17-20, SOC 2 CC7.4 — IR plan is documented, IR runbook is in flight, IR-team is engaged.",
779
+ "audit_evidence": "Documented IR plan, IR runbook, IR-team activation record, incident ticket with timeline, regulator notification filings.",
780
+ "reality_test": "For the active incident: confirm (a) maintainer credentials across every ecosystem (npm + PyPI + GitHub + cloud + AI-assistant config + secret store) are rotated within 4 hours of detection, (b) install-window audit completed for every host that may have run a compromised install, (c) AI-assistant config exfil scope is documented and persistence hooks removed from every affected workstation, (d) downstream-consumer notification is filed via OpenSSF MAL + GHSA + npm-advisory / PyPI-advisory if the operator publishes packages, (e) provenance-revocation entries are filed for every affected package version. Theater verdict if any of (a)-(e) miss or are not in the IR runbook as named primitives.",
781
+ "theater_verdict_if_gap": "Operator demonstrates an audit-clean IR programme that processes the supply-chain compromise as an ad-hoc incident without named primitives for ecosystem-package recovery. Either (a) update the IR plan + runbook to name maintainer-credential rotation + install-window audit + AI-assistant config exfil + downstream-consumer notification as scenario primitives, (b) deploy tooling for each primitive (rotation runbook automation, install-window audit tooling, AI-assistant config monitoring, advisory-filing pipeline), (c) train the IR team on Shai-Hulud-family pattern, (d) integrate the OpenSSF MAL feed + GHSA into the detection pipeline so the next compromise has zero-lag detection, OR (e) generate a defensible policy exception via policy-exception-gen acknowledging the framework-coverage gap + interim compensating-control posture."
782
+ },
783
+ "framework_gap_mapping": [
784
+ {
785
+ "finding_id": "supply-chain-recovery-framework-gap",
786
+ "framework": "nist-800-53",
787
+ "claimed_control": "IR-4 — Incident Handling",
788
+ "actual_gap": "Operator-incident framing; ecosystem-package compromise lacks named sub-procedure.",
789
+ "required_control": "Add IR-4 sub-procedure for ecosystem-package compromise with named primitives: maintainer-credential rotation across npm/PyPI/GitHub/cloud/AI-assistant/secret-store, install-window audit, AI-assistant config exfil scope, downstream-consumer notification, provenance-revocation filing."
790
+ },
791
+ {
792
+ "finding_id": "supply-chain-recovery-framework-gap",
793
+ "framework": "nist-800-53",
794
+ "claimed_control": "IR-6 — Incident Reporting",
795
+ "actual_gap": "External-reporting language omits downstream-consumer audience.",
796
+ "required_control": "Extend IR-6 reporting targets to include OpenSSF MAL feed + GHSA + npm-advisory + PyPI-advisory + ecosystem-specific advisories when operator publishes packages affected by the compromise."
797
+ },
798
+ {
799
+ "finding_id": "supply-chain-recovery-framework-gap",
800
+ "framework": "nist-800-53",
801
+ "claimed_control": "IR-8 — Incident Response Plan",
802
+ "actual_gap": "Plans rarely name ecosystem-package compromise scenarios; AI-assistant config exfil not addressed.",
803
+ "required_control": "Mandate IR-8 plans name supply-chain-recovery as scenario with AI-assistant config exfil scope explicit."
804
+ },
805
+ {
806
+ "finding_id": "supply-chain-recovery-framework-gap",
807
+ "framework": "nist-800-53",
808
+ "claimed_control": "SR-3 — Supply Chain Controls and Processes",
809
+ "actual_gap": "Pre-incident framing; no bridge to IR-4 for post-incident recovery.",
810
+ "required_control": "Define SR-3 → IR-4 bridge: pre-incident supply-chain controls trigger documented post-incident recovery playbook."
811
+ },
812
+ {
813
+ "finding_id": "supply-chain-recovery-framework-gap",
814
+ "framework": "iso-27001-2022",
815
+ "claimed_control": "A.5.24 — Information security incident management planning and preparation",
816
+ "actual_gap": "Operator-owned-incident framing; ecosystem-package compromise sub-process absent.",
817
+ "required_control": "Amendment requiring ecosystem-package compromise as named scenario with documented recovery primitives."
818
+ },
819
+ {
820
+ "finding_id": "supply-chain-recovery-framework-gap",
821
+ "framework": "iso-27001-2022",
822
+ "claimed_control": "A.5.26 — Response to information security incidents",
823
+ "actual_gap": "Response workflows omit cross-ecosystem rotation, install-window audit, downstream notification.",
824
+ "required_control": "Amend A.5.26 implementation guidance: response workflows must include cross-ecosystem rotation matrix + install-window audit tooling + downstream-consumer notification path for supply-chain class."
825
+ },
826
+ {
827
+ "finding_id": "supply-chain-recovery-framework-gap",
828
+ "framework": "iso-27001-2022",
829
+ "claimed_control": "A.5.27 — Learning from information security incidents",
830
+ "actual_gap": "Operator-internal lessons; cross-ecosystem lessons unanchored.",
831
+ "required_control": "Bind A.5.27 to ecosystem-wide learning channels: OpenSSF MAL feed contribution, GHSA advisory authoring, post-incident community publication."
832
+ },
833
+ {
834
+ "finding_id": "supply-chain-recovery-framework-gap",
835
+ "framework": "nis2",
836
+ "claimed_control": "Art.21(2)(f) — Crisis management",
837
+ "actual_gap": "Crisis-management measures do not specify supply-chain-recovery primitives.",
838
+ "required_control": "Implementing act binding essential-entity crisis-management plans to include ecosystem-package compromise recovery playbook with named primitives."
839
+ },
840
+ {
841
+ "finding_id": "supply-chain-recovery-framework-gap",
842
+ "framework": "dora",
843
+ "claimed_control": "Art.17-20 — ICT-related incident management",
844
+ "actual_gap": "Classification anchored on operator-side impact; upstream-source compromise misses early-detection window.",
845
+ "required_control": "RTS/ITS adding ecosystem-package compromise as classification axis triggering DORA Art.19 4h notification when financial-entity packages are affected."
846
+ },
847
+ {
848
+ "finding_id": "supply-chain-recovery-framework-gap",
849
+ "framework": "eu-cra",
850
+ "claimed_control": "Art.14 — Coordinated vulnerability disclosure / actively-exploited reporting",
851
+ "actual_gap": "Binds manufacturer; consumer-only operators have inbound disclosure but no recovery primitive.",
852
+ "required_control": "Implementing act extending Art.14 with consumer-side recovery guidance: ecosystem-package compromise triggers documented consumer recovery workflow including credential rotation + install-window audit."
853
+ },
854
+ {
855
+ "finding_id": "supply-chain-recovery-framework-gap",
856
+ "framework": "soc2",
857
+ "claimed_control": "CC7.4 — Incident response",
858
+ "actual_gap": "Operator-incident framing inherits NIST gap.",
859
+ "required_control": "Trust-services-criteria update: CC7.4 evidence must include ecosystem-package compromise scenario in IR plan + named recovery primitives."
860
+ }
861
+ ],
862
+ "escalation_criteria": [
863
+ {
864
+ "condition": "operator-published-package-republish == fired",
865
+ "action": "page_on_call"
866
+ },
867
+ {
868
+ "condition": "blast_radius_score >= 4",
869
+ "action": "page_on_call"
870
+ },
871
+ {
872
+ "condition": "ai-assistant-config-mutated == fired",
873
+ "action": "trigger_playbook",
874
+ "target_playbook": "mcp"
875
+ },
876
+ {
877
+ "condition": "any_credential_class_exfil'd_includes_sso_admin == true",
878
+ "action": "trigger_playbook",
879
+ "target_playbook": "idp-incident"
880
+ },
881
+ {
882
+ "condition": "credential-store-touched-during-window == fired",
883
+ "action": "trigger_playbook",
884
+ "target_playbook": "cred-stores"
885
+ },
886
+ {
887
+ "condition": "operator-published-package-republish == fired",
888
+ "action": "trigger_playbook",
889
+ "target_playbook": "sbom"
890
+ },
891
+ {
892
+ "condition": "compliance_theater_check.verdict == 'theater'",
893
+ "action": "notify_legal"
894
+ },
895
+ {
896
+ "condition": "operator-published-package-republish == fired AND jurisdiction_obligations contains 'EU'",
897
+ "action": "notify_legal"
898
+ }
899
+ ]
900
+ },
901
+ "validate": {
902
+ "remediation_paths": [
903
+ {
904
+ "id": "exhaustive-maintainer-credential-rotation",
905
+ "description": "NEW-CTRL-050: Rotate every credential across every ecosystem the worm could have exfil'd. Per ecosystem: npm tokens (npm token revoke + recreate), PyPI tokens (PyPI account → token revoke + recreate), GitHub PATs + Apps installation tokens (gh auth refresh + revoke), cloud SDK credentials (aws iam delete-access-key + recreate / gcloud auth revoke + login / az login --use-device-code), SSH private keys (revoke from authorized_keys on every endpoint + regenerate), AI-assistant config tokens (claude logout + relogin, codeium auth + relogin, cursor auth + relogin), secret-store CLI sessions (gh auth logout / vault token revoke / doctl auth init / gcloud auth revoke). Confirm rotation propagated with synthetic test per credential.",
906
+ "preconditions": [
907
+ "operator_holds_rotation_authority == true",
908
+ "rotation_runbook_documented == true OR ad_hoc_rotation_acceptable_within_4h == true"
909
+ ],
910
+ "priority": 1,
911
+ "compensating_controls": [
912
+ "rotation_recorded_in_secret_store_audit_log",
913
+ "synthetic_test_validates_new_credential",
914
+ "old_token_rejection_confirmed"
915
+ ],
916
+ "estimated_time_hours": 8
917
+ },
918
+ {
919
+ "id": "install-window-audit-and-remediation",
920
+ "description": "NEW-CTRL-051: For every host that may have run a compromised install: (a) enumerate the install via npm + pip + lock-file diff, (b) identify the postinstall execution timestamp, (c) audit credential-store access timestamps + network egress in the 5-minute window post-install, (d) for hits, treat the host as compromised and follow the operator's host-isolation + re-imaging procedure, (e) for non-hits, document the audit as evidence the host is clean.",
921
+ "preconditions": [
922
+ "install-history-per-host_obtainable == true",
923
+ "host_isolation_authority == true"
924
+ ],
925
+ "priority": 1,
926
+ "compensating_controls": [
927
+ "host_isolation_during_audit",
928
+ "fresh_workstation_provisioning_for_affected_developers"
929
+ ],
930
+ "estimated_time_hours": 24
931
+ },
932
+ {
933
+ "id": "ai-assistant-config-cleanup",
934
+ "description": "NEW-CTRL-052: For every host with AI-assistant installs that ran a compromised postinstall: (a) snapshot the current AI-assistant config files, (b) restore from pre-compromise baseline OR remove all non-allowlisted MCP servers + startup hooks, (c) re-authenticate the AI assistant with rotated credentials, (d) verify no persistence remains by restarting the AI assistant and confirming clean startup. AI-assistant config cleanup is first-class — Shai-Hulud-family explicitly persists here.",
935
+ "preconditions": [
936
+ "ai_assistant_config_baseline_or_allowlist_available == true",
937
+ "operator_can_re_authenticate_ai_assistant == true"
938
+ ],
939
+ "priority": 1,
940
+ "compensating_controls": [
941
+ "ai_assistant_baseline_attestation",
942
+ "weekly_ai_assistant_config_drift_scan"
943
+ ],
944
+ "estimated_time_hours": 6
945
+ },
946
+ {
947
+ "id": "downstream-consumer-notification",
948
+ "description": "If operator-published-package-republish fired: file advisories on OpenSSF MAL feed + GHSA + npm-advisory / PyPI-advisory naming the affected package + malicious version + recovery guidance for consumers. Yank or deprecate the affected version. Push notification to known downstream consumers via the operator's published contact channels.",
949
+ "preconditions": [
950
+ "operator_publishes_packages == true",
951
+ "operator_can_file_advisories == true"
952
+ ],
953
+ "priority": 2,
954
+ "compensating_controls": [
955
+ "advisory_filed_within_24h",
956
+ "yank_or_deprecate_within_4h",
957
+ "consumer_contact_archive_updated"
958
+ ],
959
+ "estimated_time_hours": 12
960
+ },
961
+ {
962
+ "id": "provenance-revocation-and-re-establishment",
963
+ "description": "For every affected operator-published version: file sigstore revocation entries, npm provenance revocation, GHSA security advisory. Re-establish provenance for the clean version: ensure new release goes through SLSA-L3-conformant pipeline with the rotated signing key.",
964
+ "preconditions": [
965
+ "operator_holds_provenance_filing_authority == true",
966
+ "slsa_l3_pipeline_operational == true"
967
+ ],
968
+ "priority": 3,
969
+ "compensating_controls": [
970
+ "provenance_revocation_filed",
971
+ "clean_release_provenance_attested"
972
+ ],
973
+ "estimated_time_hours": 8
974
+ },
975
+ {
976
+ "id": "ir-plan-update-supply-chain-scenario",
977
+ "description": "Update the operator's IR plan + IR runbook to name supply-chain-recovery as a scenario with the four NEW-CTRL primitives. Train the IR team. Add the OpenSSF MAL feed + GHSA + npm-advisory pipeline to detection.",
978
+ "preconditions": [
979
+ "ir_plan_ownership_attested == true"
980
+ ],
981
+ "priority": 4,
982
+ "compensating_controls": [
983
+ "ir_team_training_recorded",
984
+ "feed_ingestion_attested"
985
+ ],
986
+ "estimated_time_hours": 24
987
+ },
988
+ {
989
+ "id": "policy-exception",
990
+ "description": "For recovery primitives that cannot be completed within the jurisdiction's window: generate auditor-ready policy exception with compensating controls, time-bound risk acceptance, and remediation milestones. Typical blockers: legacy host without re-imaging window, vendor refuses to rotate a shared maintainer credential, downstream-consumer notification depends on third-party advisory pipeline outside operator control.",
991
+ "preconditions": [
992
+ "remediation_paths[1..6] partially blocked",
993
+ "ciso_acceptance_obtainable == true"
994
+ ],
995
+ "priority": 7,
996
+ "compensating_controls": [
997
+ "enhanced_endpoint_monitoring",
998
+ "compensating_network_segmentation",
999
+ "weekly_exception_register_review"
1000
+ ],
1001
+ "estimated_time_hours": 6
1002
+ }
1003
+ ],
1004
+ "validation_tests": [
1005
+ {
1006
+ "id": "rotated-credential-rejection",
1007
+ "test": "Post-rotation: attempt to use the OLD credential against each ecosystem (npm publish with old token, gh auth with old PAT, aws sts get-caller-identity with old keys, claude login with old session token). Confirm rejection.",
1008
+ "expected_result": "Every old credential rejected across every ecosystem.",
1009
+ "test_type": "negative"
1010
+ },
1011
+ {
1012
+ "id": "install-window-audit-completeness",
1013
+ "test": "For each host enumerated in install-history-per-host: confirm an audit record exists with (a) install timestamp, (b) postinstall execution result, (c) credential-store access scan, (d) network egress scan, (e) host disposition (clean / compromised + isolated / compromised + re-imaged).",
1014
+ "expected_result": "100% of in-scope hosts have a complete audit record.",
1015
+ "test_type": "functional"
1016
+ },
1017
+ {
1018
+ "id": "ai-assistant-config-clean",
1019
+ "test": "Post-cleanup: snapshot each AI-assistant config and confirm match to baseline OR allowlist. Restart the AI assistant; confirm no unexpected MCP server connection, no unexpected startup-hook execution.",
1020
+ "expected_result": "Config snapshot matches baseline / allowlist; AI assistant starts cleanly.",
1021
+ "test_type": "functional"
1022
+ },
1023
+ {
1024
+ "id": "downstream-advisory-filed",
1025
+ "test": "If operator publishes packages: confirm OpenSSF MAL + GHSA + npm-advisory / PyPI-advisory entries exist naming the affected package + version + recovery guidance.",
1026
+ "expected_result": "Advisory entries filed across all applicable channels.",
1027
+ "test_type": "functional"
1028
+ },
1029
+ {
1030
+ "id": "yank-or-deprecation-confirmed",
1031
+ "test": "For each affected version: confirm `npm view <pkg>@<ver> deprecated` returns deprecation reason OR `pip download <pkg>==<ver>` reports yanked / withdrawn.",
1032
+ "expected_result": "Every affected version yanked / deprecated.",
1033
+ "test_type": "functional"
1034
+ },
1035
+ {
1036
+ "id": "provenance-re-established",
1037
+ "test": "For the clean (post-incident) release of each affected operator-published package: confirm SLSA-L3 provenance attestation + sigstore signature with the rotated key.",
1038
+ "expected_result": "Provenance attestation valid; signature traces to rotated key.",
1039
+ "test_type": "functional"
1040
+ },
1041
+ {
1042
+ "id": "ir-plan-supply-chain-scenario-present",
1043
+ "test": "Read the updated IR plan + IR runbook. Assert supply-chain-recovery scenario is named with the four NEW-CTRL primitives (rotation + install-window audit + AI-assistant config cleanup + downstream-consumer notification).",
1044
+ "expected_result": "IR plan / runbook has named supply-chain-recovery scenario with all four primitives.",
1045
+ "test_type": "functional"
1046
+ },
1047
+ {
1048
+ "id": "no-regression-postinstall-execution",
1049
+ "test": "On a fresh canary host, attempt `npm install <compromised-package>@<malicious-version>` (against a local mirror that still holds the version for testing). Confirm the host's endpoint controls (allowlisting, egress filtering, postinstall script restriction) prevent execution OR cleanly contain it.",
1050
+ "expected_result": "Endpoint controls prevent or contain execution; the canary host is unaffected.",
1051
+ "test_type": "exploit_replay"
1052
+ }
1053
+ ],
1054
+ "residual_risk_statement": {
1055
+ "risk": "Operator retains residual risk from supply-chain compromise across (a) credentials that may have been exfil'd before rotation completed, (b) downstream consumers who installed the compromised version before advisories landed, (c) AI-assistant persistence on hosts not yet audited, (d) future-iteration of the Shai-Hulud family targeting yet-unenumerated config files.",
1056
+ "why_remains": "Rotation closes future-publish + future-auth windows but cannot retract credential exposure during the compromise window. Downstream consumers install at their own cadence; some will install before yanking propagates. AI-assistant config exfil scope expands as new AI assistants ship config files. The Shai-Hulud family is actively maintained by TeamPCP + copycats; recovery primitives encoded today may need extension within the next cycle.",
1057
+ "acceptance_level": "ciso",
1058
+ "compensating_controls_in_place": [
1059
+ "exhaustive_credential_rotation_completed",
1060
+ "install_window_audit_documented",
1061
+ "ai_assistant_config_cleanup_completed",
1062
+ "downstream_advisory_filed",
1063
+ "provenance_re_established",
1064
+ "ir_plan_updated_with_supply_chain_scenario",
1065
+ "enhanced_monitoring_post_incident"
1066
+ ]
1067
+ },
1068
+ "evidence_requirements": [
1069
+ {
1070
+ "evidence_type": "attestation",
1071
+ "description": "Credential rotation completion record across every ecosystem with old-token rejection confirmed via synthetic test; signed.",
1072
+ "retention_period": "7_years",
1073
+ "framework_satisfied": [
1074
+ "nist-800-53-IR-4",
1075
+ "iso-27001-2022-A.5.26",
1076
+ "nis2-art21-2f",
1077
+ "soc2-CC7.4"
1078
+ ]
1079
+ },
1080
+ {
1081
+ "evidence_type": "scan_report",
1082
+ "description": "Install-window audit record per in-scope host with disposition + audit timestamps.",
1083
+ "retention_period": "7_years",
1084
+ "framework_satisfied": [
1085
+ "nist-800-53-IR-4",
1086
+ "nist-800-53-IR-5",
1087
+ "iso-27001-2022-A.5.26",
1088
+ "dora-art17"
1089
+ ]
1090
+ },
1091
+ {
1092
+ "evidence_type": "attestation",
1093
+ "description": "AI-assistant config cleanup attestation per affected host with baseline-match confirmation.",
1094
+ "retention_period": "7_years",
1095
+ "framework_satisfied": [
1096
+ "nist-800-53-IR-4",
1097
+ "iso-27001-2022-A.5.26"
1098
+ ]
1099
+ },
1100
+ {
1101
+ "evidence_type": "scan_report",
1102
+ "description": "Downstream-consumer advisory filing records across OpenSSF MAL + GHSA + ecosystem-specific advisories.",
1103
+ "retention_period": "7_years",
1104
+ "framework_satisfied": [
1105
+ "nist-800-53-IR-6",
1106
+ "iso-27001-2022-A.5.27",
1107
+ "eu-cra-art-14"
1108
+ ]
1109
+ },
1110
+ {
1111
+ "evidence_type": "config_diff",
1112
+ "description": "IR plan + IR runbook diff showing addition of supply-chain-recovery scenario with the four NEW-CTRL primitives.",
1113
+ "retention_period": "audit_cycle",
1114
+ "framework_satisfied": [
1115
+ "nist-800-53-IR-8",
1116
+ "iso-27001-2022-A.5.24",
1117
+ "nis2-art21-2f",
1118
+ "soc2-CC7.4"
1119
+ ]
1120
+ },
1121
+ {
1122
+ "evidence_type": "exploit_replay_negative",
1123
+ "description": "Canary-host install-of-malicious-version test confirming endpoint controls prevent or contain execution.",
1124
+ "retention_period": "1_year",
1125
+ "framework_satisfied": [
1126
+ "soc2-CC7.4",
1127
+ "iso-27001-2022-A.5.26"
1128
+ ]
1129
+ },
1130
+ {
1131
+ "evidence_type": "attestation",
1132
+ "description": "Signed exceptd attestation file with evidence_hash, affected-package inventory, host disposition summary, credential rotation summary, downstream advisory filing summary, residual risk acceptance.",
1133
+ "retention_period": "7_years",
1134
+ "framework_satisfied": [
1135
+ "nist-800-53-CA-7",
1136
+ "iso-27001-2022-A.5.36",
1137
+ "nis2-art21-2f"
1138
+ ]
1139
+ }
1140
+ ],
1141
+ "regression_trigger": [
1142
+ {
1143
+ "condition": "new_shai_hulud_family_advisory_published",
1144
+ "interval": "on_event"
1145
+ },
1146
+ {
1147
+ "condition": "new_compromised_version_for_inventoried_dependency",
1148
+ "interval": "on_event"
1149
+ },
1150
+ {
1151
+ "condition": "ai_assistant_config_drift_detected",
1152
+ "interval": "on_event"
1153
+ },
1154
+ {
1155
+ "condition": "new_maintainer_credential_issued",
1156
+ "interval": "on_event"
1157
+ },
1158
+ {
1159
+ "condition": "weekly_post_incident",
1160
+ "interval": "7d"
1161
+ },
1162
+ {
1163
+ "condition": "monthly_steady_state",
1164
+ "interval": "30d"
1165
+ }
1166
+ ]
1167
+ },
1168
+ "close": {
1169
+ "evidence_package": {
1170
+ "bundle_format": "csaf-2.0",
1171
+ "contents": [
1172
+ "all_validation_tests_passed",
1173
+ "credential_rotation_completion_record",
1174
+ "install_window_audit_report",
1175
+ "ai_assistant_config_cleanup_attestation",
1176
+ "downstream_advisory_filing_records",
1177
+ "provenance_re_establishment_record",
1178
+ "ir_plan_diff",
1179
+ "exploit_replay_negative",
1180
+ "framework_gap_mapping",
1181
+ "compliance_theater_verdict",
1182
+ "residual_risk_statement",
1183
+ "attestation"
1184
+ ],
1185
+ "destination": "local_only",
1186
+ "signed": true
1187
+ },
1188
+ "learning_loop": {
1189
+ "enabled": true,
1190
+ "lesson_template": {
1191
+ "attack_vector": "Ecosystem-package compromise (Shai-Hulud family or successor) — malicious version published under compromised maintainer credentials, postinstall harvests credentials across npm + cloud + AI-assistant config + secret store, republishes through operator's publish surface, persists via AI-assistant startup hooks.",
1192
+ "control_gap": "Incident-response controls do not name supply-chain-recovery as a scenario with the NEW-CTRL-050 / 051 / 052 primitives. AI-assistant config exfil is not first-class in any framework. Downstream-consumer notification is undefined as an external-reporting target.",
1193
+ "framework_gap": "NIST IR-4 + IR-6 + IR-8 + SR-3, ISO A.5.24 + A.5.26 + A.5.27, NIS2 Art.21(2)(f), DORA Art.17-20, EU CRA Art.14, SOC 2 CC7.4, UK CAF D1 all permit IR programmes that omit supply-chain-recovery primitives as compliant. Framework cadence ~270 days behind operational pattern establishment.",
1194
+ "new_control_requirement": "Add 'supply-chain-recovery' as named scenario across the eleven framework controls requiring: (a) exhaustive maintainer-credential rotation across npm + PyPI + GitHub + cloud + AI-assistant + secret-store (NEW-CTRL-050), (b) install-window audit across every host that may have run a compromised install (NEW-CTRL-051), (c) AI-assistant config exfil scope as first-class recovery primitive (NEW-CTRL-052), (d) downstream-consumer notification via OpenSSF MAL + GHSA + ecosystem-specific advisories, (e) provenance revocation + re-establishment with rotated keys."
1195
+ },
1196
+ "feeds_back_to_skills": [
1197
+ "supply-chain-integrity",
1198
+ "incident-response-playbook",
1199
+ "ransomware-response",
1200
+ "coordinated-vuln-disclosure",
1201
+ "framework-gap-analysis",
1202
+ "compliance-theater",
1203
+ "zeroday-gap-learn"
1204
+ ]
1205
+ },
1206
+ "notification_actions": [
1207
+ {
1208
+ "obligation_ref": "EU/NIS2 Art.23 24h",
1209
+ "deadline": "computed_at_runtime",
1210
+ "recipient": "internal_legal",
1211
+ "evidence_attached": [
1212
+ "compromised_maintainer_account_inventory",
1213
+ "affected_install_window_estimate",
1214
+ "downstream_blast_radius_estimate",
1215
+ "containment_record"
1216
+ ],
1217
+ "draft_notification": "Initial NIS2 Art.23 24-hour early-warning notification: Supply-chain compromise affecting ${affected_package_count} package(s) (${shai_hulud_family_name} family). Compromise window: ${compromise_window_start} to ${compromise_window_end}. Affected operator hosts: ${affected_host_count}. Operator-published packages republished: ${republished_count}. Containment in place: ${containment_record}. Full incident assessment to follow within 72 hours per Art.23(4)."
1218
+ },
1219
+ {
1220
+ "obligation_ref": "EU/DORA Art.19 4h",
1221
+ "deadline": "computed_at_runtime",
1222
+ "recipient": "internal_legal",
1223
+ "evidence_attached": [
1224
+ "ict_critical_function_impact",
1225
+ "ict_third_party_dependencies_affected",
1226
+ "containment_record"
1227
+ ],
1228
+ "draft_notification": "DORA Art.19 initial notification: Major ICT-related incident — supply-chain compromise affecting ICT services supporting ${critical_or_important_functions}. Affected ICT third-party dependencies: ${affected_dependencies}. Containment posture: ${containment_record}. Full classification + impact assessment to follow within statutory windows."
1229
+ },
1230
+ {
1231
+ "obligation_ref": "EU/EU CRA Art.14 24h",
1232
+ "deadline": "computed_at_runtime",
1233
+ "recipient": "internal_legal",
1234
+ "evidence_attached": [
1235
+ "actively_exploited_assessment",
1236
+ "user_notification_draft",
1237
+ "affected_product_inventory"
1238
+ ],
1239
+ "draft_notification": "EU CRA Art.14 notification: actively-exploited vulnerability in ${affected_product_inventory} arising from supply-chain compromise. ${manufacturer_name} attests the affected version(s) are yanked/deprecated and downstream advisories filed. User-notification draft attached for review."
1240
+ },
1241
+ {
1242
+ "obligation_ref": "EU/GDPR Art.33 72h",
1243
+ "deadline": "computed_at_runtime",
1244
+ "recipient": "internal_legal",
1245
+ "evidence_attached": [
1246
+ "data_subject_impact_assessment",
1247
+ "exfiltration_window_estimate"
1248
+ ],
1249
+ "draft_notification": "GDPR Art.33 notification: personal data breach potentially affecting ${data_subjects_estimate} data subjects via supply-chain credential exfil on operator hosts. Exfil window: ${exfil_window}. Notification to data subjects: ${data_subject_notification_status}."
1250
+ },
1251
+ {
1252
+ "obligation_ref": "US-Federal/SEC Item 1.05 (8-K) 96h",
1253
+ "deadline": "computed_at_runtime",
1254
+ "recipient": "internal_legal",
1255
+ "evidence_attached": [
1256
+ "material_impact_determination",
1257
+ "incident_description"
1258
+ ],
1259
+ "draft_notification": "SEC Item 1.05 8-K disclosure draft: Material cybersecurity incident — supply-chain compromise affecting ${affected_systems}. Materiality determination: ${materiality_justification}. Remediation status: ${remediation_status}."
1260
+ }
1261
+ ],
1262
+ "exception_generation": {
1263
+ "trigger_condition": "remediation_blocked == true OR (provider_does_not_expose_required_primitive == true AND alternative_provider_migration_eta > jurisdiction_window)",
1264
+ "exception_template": {
1265
+ "scope": "Supply-chain-recovery residual risk across ${affected_host_count} host(s) + ${affected_package_count} affected package(s). Remediation paths 1-6 partially blocked by ${blocking_factors}.",
1266
+ "duration": "until_remediation_complete_or_30d",
1267
+ "compensating_controls": [
1268
+ "enhanced_endpoint_monitoring_for_affected_hosts",
1269
+ "network_segmentation_for_unisolatable_hosts",
1270
+ "weekly_credential_rotation_audit",
1271
+ "weekly_ai_assistant_config_drift_scan",
1272
+ "downstream_consumer_advisory_pipeline_monitored",
1273
+ "openssf_mal_feed_ingestion_attested"
1274
+ ],
1275
+ "risk_acceptance_owner": "ciso",
1276
+ "auditor_ready_language": "Pursuant to ${framework_id} ${control_id}, the organisation documents a time-bound risk acceptance for supply-chain-recovery residual risk across ${affected_host_count} host(s) + ${affected_package_count} affected package(s). Compromise family: ${shai_hulud_family_or_successor}. Blocking factors: ${blocking_factors}. The organisation acknowledges that current framework controls do not specify ecosystem-package compromise as a named IR scenario with NEW-CTRL-050 / NEW-CTRL-051 / NEW-CTRL-052 primitives and that this gap is documented in ${exceptd_framework_gap_mapping_ref}. Compensating controls in place: ${compensating_controls}. Remediation milestones: ${remediation_milestones}. Risk accepted by ${ciso_name} on ${acceptance_date}. Time-bound until ${duration_expiry}. The exception will be re-evaluated on (a) remediation completion, (b) new Shai-Hulud-family advisory affecting the operator, (c) scheduled expiry, OR (d) framework amendment landing the missing controls — whichever is first."
1277
+ }
1278
+ },
1279
+ "regression_schedule": {
1280
+ "next_run": "computed_at_runtime",
1281
+ "trigger": "both",
1282
+ "notify_on_skip": true
1283
+ }
1284
+ }
1285
+ },
1286
+ "directives": [
1287
+ {
1288
+ "id": "full-recovery-sequence",
1289
+ "title": "Full post-compromise recovery — credential rotation + install-window audit + AI-assistant config cleanup + downstream notification + provenance re-establishment",
1290
+ "applies_to": {
1291
+ "always": true
1292
+ }
1293
+ },
1294
+ {
1295
+ "id": "shai-hulud-family-active-incident",
1296
+ "title": "Active Shai-Hulud-family incident response (MAL-2026-SHAI-HULUD-OSS / Mini Shai-Hulud / TanStack-mini)",
1297
+ "applies_to": {
1298
+ "cve": "MAL-2026-SHAI-HULUD-OSS"
1299
+ },
1300
+ "phase_overrides": {
1301
+ "direct": {
1302
+ "rwep_threshold": {
1303
+ "escalate": 90,
1304
+ "monitor": 70,
1305
+ "close": 30
1306
+ }
1307
+ }
1308
+ }
1309
+ },
1310
+ {
1311
+ "id": "tanstack-mini-incident",
1312
+ "title": "TanStack-mini variant recovery (MAL-2026-TANSTACK-MINI / 42 @tanstack/* packages)",
1313
+ "applies_to": {
1314
+ "cve": "MAL-2026-TANSTACK-MINI"
1315
+ }
1316
+ },
1317
+ {
1318
+ "id": "node-ipc-stealer-incident",
1319
+ "title": "node-ipc-stealer variant recovery (MAL-2026-NODE-IPC-STEALER)",
1320
+ "applies_to": {
1321
+ "cve": "MAL-2026-NODE-IPC-STEALER"
1322
+ }
1323
+ },
1324
+ {
1325
+ "id": "worm-via-github-actions",
1326
+ "title": "Worm-via-GitHub-Actions class recovery (CVE-2026-45321)",
1327
+ "applies_to": {
1328
+ "cve": "CVE-2026-45321"
1329
+ }
1330
+ }
1331
+ ]
1332
+ }