@blamejs/exceptd-skills 0.10.1 → 0.10.3

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,1792 @@
1
+ {
2
+ "_meta": {
3
+ "id": "library-author",
4
+ "version": "1.0.0",
5
+ "last_threat_review": "2026-05-12",
6
+ "threat_currency_score": 95,
7
+ "changelog": [
8
+ {
9
+ "version": "1.0.0",
10
+ "date": "2026-05-12",
11
+ "summary": "Initial seven-phase library-author / framework-author / SDK-publisher playbook. Audits the upstream / publisher side of the supply chain: vendored dependencies, lockfile pinning depth + integrity, SBOM signing + format + transitive completeness, SLSA build provenance + Sigstore Rekor entries + in-toto attestation chains, npm/PyPI/crates publish-time provenance, VEX issuance posture (am I emitting VEX for CVEs filed against my product?), coordinated-vuln-disclosure path (security.txt + SECURITY.md + CSAF advisory pipeline), tag + branch protection on release branches, GitHub Actions OIDC vs static publishing tokens, reproducible-build claims, and Ed25519 / cosign skill-signing for AI-tool publishers. Distinct from the install-side `sbom` playbook: this one investigates what YOU ship to thousands of downstream consumers, not what's installed on your host.",
12
+ "framework_gaps_updated": [
13
+ "nist-800-218-PS-3",
14
+ "nist-800-218-PW-4",
15
+ "nist-800-53-SR-3",
16
+ "nist-800-53-SR-4",
17
+ "nist-800-53-SR-5",
18
+ "iso-27001-2022-A.8.30",
19
+ "iso-27001-2022-A.5.20",
20
+ "eu-cra-art10",
21
+ "eu-cra-art13",
22
+ "eu-cra-art14",
23
+ "nis2-art21-2d",
24
+ "dora-art28",
25
+ "cmmc-SI.L2-3.4.4"
26
+ ]
27
+ }
28
+ ],
29
+ "owner": "@blamejs/supply-chain",
30
+ "air_gap_mode": false,
31
+ "scope": "code",
32
+ "preconditions": [
33
+ {
34
+ "id": "repo-walk-access",
35
+ "description": "Agent must be able to read the current repo: .git/, .github/workflows/, package.json / pyproject.toml / Cargo.toml / go.mod / Gemfile, lockfiles, SECURITY.md, and any committed SBOM / VEX / signing-key artifacts.",
36
+ "check": "agent_has_filesystem_read == true AND cwd_is_git_repo == true",
37
+ "on_fail": "halt"
38
+ },
39
+ {
40
+ "id": "publishable-artifact-evidence",
41
+ "description": "The repo must show some sign that it publishes artifacts (package.json with publishConfig, pyproject.toml with [project] / [tool.poetry] publish metadata, Cargo.toml with [package].publish != false, .github/workflows containing a publish/release step, GoReleaser config, or a tagged-release history). Otherwise this playbook has nothing to audit.",
42
+ "check": "exists_any('package.json', 'pyproject.toml', 'Cargo.toml', 'go.mod', '*.gemspec', '.goreleaser.yml', '.github/workflows/release*.yml', '.github/workflows/publish*.yml') == true",
43
+ "on_fail": "warn"
44
+ }
45
+ ],
46
+ "mutex": ["secrets"],
47
+ "feeds_into": [
48
+ {
49
+ "playbook_id": "sbom",
50
+ "condition": "always"
51
+ },
52
+ {
53
+ "playbook_id": "framework",
54
+ "condition": "analyze.compliance_theater_check.verdict == 'theater'"
55
+ },
56
+ {
57
+ "playbook_id": "compliance-theater",
58
+ "condition": "analyze.compliance_theater_check.verdict == 'theater'"
59
+ }
60
+ ]
61
+ },
62
+ "domain": {
63
+ "name": "Library / framework / SDK publisher supply-chain posture",
64
+ "attack_class": "supply-chain",
65
+ "atlas_refs": [
66
+ "AML.T0010",
67
+ "AML.T0018"
68
+ ],
69
+ "attack_refs": [
70
+ "T1195.001",
71
+ "T1195.002",
72
+ "T1554",
73
+ "T1199"
74
+ ],
75
+ "cve_refs": [],
76
+ "cwe_refs": [
77
+ "CWE-1357",
78
+ "CWE-1395",
79
+ "CWE-494",
80
+ "CWE-829",
81
+ "CWE-353",
82
+ "CWE-345"
83
+ ],
84
+ "d3fend_refs": [
85
+ "D3-CBAN",
86
+ "D3-EAL",
87
+ "D3-EHB"
88
+ ],
89
+ "frameworks_in_scope": [
90
+ "nist-800-53",
91
+ "nist-csf-2",
92
+ "iso-27001-2022",
93
+ "soc2",
94
+ "nis2",
95
+ "dora",
96
+ "eu-cra",
97
+ "uk-caf",
98
+ "au-ism",
99
+ "au-essential-8",
100
+ "cmmc"
101
+ ]
102
+ },
103
+ "phases": {
104
+ "govern": {
105
+ "jurisdiction_obligations": [
106
+ {
107
+ "jurisdiction": "EU",
108
+ "regulation": "EU CRA Art.14",
109
+ "obligation": "notify_actively_exploited_vulnerability",
110
+ "window_hours": 24,
111
+ "clock_starts": "detect_confirmed",
112
+ "evidence_required": [
113
+ "affected_product_identification",
114
+ "exploitation_evidence",
115
+ "mitigation_status",
116
+ "csaf_advisory_draft"
117
+ ]
118
+ },
119
+ {
120
+ "jurisdiction": "EU",
121
+ "regulation": "EU CRA Art.14",
122
+ "obligation": "notify_actively_exploited_vulnerability_full",
123
+ "window_hours": 72,
124
+ "clock_starts": "analyze_complete",
125
+ "evidence_required": [
126
+ "full_vulnerability_assessment",
127
+ "corrective_measures",
128
+ "published_csaf_advisory"
129
+ ]
130
+ },
131
+ {
132
+ "jurisdiction": "EU",
133
+ "regulation": "EU CRA Art.13 / Annex I",
134
+ "obligation": "submit_technical_documentation",
135
+ "window_hours": 8760,
136
+ "clock_starts": "manual",
137
+ "evidence_required": [
138
+ "sbom_per_product",
139
+ "conformity_assessment",
140
+ "vulnerability_handling_procedure",
141
+ "security_update_record",
142
+ "coordinated_disclosure_policy"
143
+ ]
144
+ },
145
+ {
146
+ "jurisdiction": "EU",
147
+ "regulation": "EU CRA Art.10",
148
+ "obligation": "maintain_security_update_obligation",
149
+ "window_hours": 43800,
150
+ "clock_starts": "manual",
151
+ "evidence_required": [
152
+ "five_year_security_update_commitment",
153
+ "support_lifecycle_record",
154
+ "end_of_support_notice_template"
155
+ ]
156
+ },
157
+ {
158
+ "jurisdiction": "EU",
159
+ "regulation": "NIS2 Art.21(2)(d)",
160
+ "obligation": "supply_chain_security_policy",
161
+ "window_hours": 720,
162
+ "clock_starts": "manual",
163
+ "evidence_required": [
164
+ "supplier_security_policy",
165
+ "third_party_risk_register",
166
+ "publisher_attestation_inventory"
167
+ ]
168
+ },
169
+ {
170
+ "jurisdiction": "EU",
171
+ "regulation": "DORA Art.28",
172
+ "obligation": "submit_third_party_ict_risk_evidence",
173
+ "window_hours": 720,
174
+ "clock_starts": "manual",
175
+ "evidence_required": [
176
+ "ict_third_party_register",
177
+ "concentration_risk_assessment",
178
+ "subcontracting_inventory"
179
+ ]
180
+ },
181
+ {
182
+ "jurisdiction": "US",
183
+ "regulation": "OMB M-22-09 / EO 14028",
184
+ "obligation": "submit_secure_software_attestation",
185
+ "window_hours": 8760,
186
+ "clock_starts": "manual",
187
+ "evidence_required": [
188
+ "cisa_secure_software_attestation_form",
189
+ "sbom_per_product",
190
+ "ssdf_alignment_evidence"
191
+ ]
192
+ },
193
+ {
194
+ "jurisdiction": "US",
195
+ "regulation": "CISA Secure-by-Design Pledge",
196
+ "obligation": "publish_self_attestation",
197
+ "window_hours": 4320,
198
+ "clock_starts": "manual",
199
+ "evidence_required": [
200
+ "secure_by_design_attestation_text",
201
+ "measurable_progress_evidence_per_goal"
202
+ ]
203
+ },
204
+ {
205
+ "jurisdiction": "UK",
206
+ "regulation": "UK CAF (NCSC) C1.b / B4.d",
207
+ "obligation": "supplier_assurance_posture",
208
+ "window_hours": 720,
209
+ "clock_starts": "manual",
210
+ "evidence_required": [
211
+ "supplier_assurance_register",
212
+ "release_pipeline_security_attestation"
213
+ ]
214
+ },
215
+ {
216
+ "jurisdiction": "AU",
217
+ "regulation": "AU ISM (ACSC) Guidelines for Software Development",
218
+ "obligation": "secure_development_evidence",
219
+ "window_hours": 720,
220
+ "clock_starts": "manual",
221
+ "evidence_required": [
222
+ "secure_development_lifecycle_record",
223
+ "signed_release_artifacts"
224
+ ]
225
+ }
226
+ ],
227
+ "theater_fingerprints": [
228
+ {
229
+ "pattern_id": "sbom-published-but-unsigned-and-request-time-generated",
230
+ "claim": "We publish an SBOM with every release per NIST SSDF PS.3.2 / EU CRA Art.13.",
231
+ "fast_detection_test": "Locate the most recent release's SBOM artifact. Verify (a) it is a committed / pipeline-published build artifact with a stable URL, NOT regenerated at request time from current state, (b) it carries a Sigstore-cosign or PGP signature, (c) the signature key chain resolves to a known publisher identity, NOT the maintainer's personal laptop key. Theater if SBOM exists but is unsigned OR is regenerated-on-demand from current dep state (which means historical releases have no immutable SBOM).",
232
+ "implicated_controls": [
233
+ "nist-800-218-PS-3",
234
+ "eu-cra-art13",
235
+ "nist-800-53-SR-4"
236
+ ]
237
+ },
238
+ {
239
+ "pattern_id": "npm-provenance-flag-but-not-enforced-in-workflow",
240
+ "claim": "We publish with npm provenance (or PyPI attestations, or cargo attestations) — SLSA Level 3 build provenance.",
241
+ "fast_detection_test": "Read .github/workflows/*.yml for the release / publish job. Confirm (a) `permissions: id-token: write` is set at the job level, (b) the npm publish command carries `--provenance` (or `publishConfig.provenance: true` in package.json), (c) the workflow runs on a GitHub-hosted runner from a protected tag-triggered event, (d) the workflow itself is pinned by SHA, not by branch / floating tag. Theater if --provenance is documented in README but not in the workflow, OR if the workflow ref is mutable (e.g. uses@actions/checkout@v4 instead of uses@actions/checkout@<sha>).",
242
+ "implicated_controls": [
243
+ "nist-800-218-PS-3",
244
+ "slsa-l3",
245
+ "nist-800-53-SR-4"
246
+ ]
247
+ },
248
+ {
249
+ "pattern_id": "release-signing-key-on-maintainer-laptop",
250
+ "claim": "We sign releases (GPG / cosign / minisign).",
251
+ "fast_detection_test": "Inspect the signature on the most recent release artifact. Verify the signing identity resolves to an OIDC identity (GitHub Actions workload, Sigstore keyless), NOT a long-lived personal key whose private half lives on a maintainer's laptop. Cross-check the .github/workflows/release*.yml for cosign / sigstore signing steps. Theater if the signature verifies but resolves to a personal email + GPG key whose rotation cadence is 'when the maintainer remembers', AND the key isn't in a managed transparency log (Sigstore Rekor, Web Key Directory).",
252
+ "implicated_controls": [
253
+ "nist-800-53-SR-4",
254
+ "nist-800-218-PW-4",
255
+ "iso-27001-2022-A.8.24"
256
+ ]
257
+ },
258
+ {
259
+ "pattern_id": "slsa-l3-claim-without-rekor-entry",
260
+ "claim": "We follow SLSA Level 3 (or Level 4) build-provenance attestation.",
261
+ "fast_detection_test": "Take the latest published release artifact. Compute its sha256. Query Sigstore Rekor (`rekor-cli search --sha <hash>`) — confirm a corresponding transparency-log entry exists with the expected workflow identity. For npm: GET https://registry.npmjs.org/<pkg> and inspect the `dist.attestations` field. Theater if SLSA L3 is claimed but Rekor / dist.attestations is empty for shipped releases — there's no immutable third-party-verifiable evidence the build happened the way the README says.",
262
+ "implicated_controls": [
263
+ "nist-800-218-PS-3",
264
+ "slsa-l3",
265
+ "in-toto-attestation"
266
+ ]
267
+ },
268
+ {
269
+ "pattern_id": "lockfile-committed-but-mid-build-resolution",
270
+ "claim": "Our build is reproducible — the lockfile is committed.",
271
+ "fast_detection_test": "Read the release workflow. Confirm the install step uses the strict mode that fails if the lockfile is stale (`npm ci`, `pnpm install --frozen-lockfile`, `pip install --require-hashes -r requirements.txt`, `cargo build --locked`, `bundle install --frozen`). Theater if the workflow uses non-frozen install commands (`npm install`, `pnpm install`, `pip install -r requirements.txt`) that may resolve mid-build and pull a substitute, OR if no registry-pinning (`registry.npmjs.org`, PyPI index URL pinning) is enforced.",
272
+ "implicated_controls": [
273
+ "nist-800-53-SR-3",
274
+ "slsa-l2",
275
+ "iso-27001-2022-A.8.30"
276
+ ]
277
+ },
278
+ {
279
+ "pattern_id": "branch-protection-main-only-tags-unprotected",
280
+ "claim": "We use branch protection — only reviewed code reaches production.",
281
+ "fast_detection_test": "Use the GitHub API `GET /repos/{owner}/{repo}/branches/{branch}/protection` AND `GET /repos/{owner}/{repo}/tags/protection`. Confirm (a) main is protected with required reviewers + status checks, (b) release tags pattern (e.g. `v*`) is protected against deletion + force-push, (c) the publish workflow only runs on tag events from protected refs. Theater if main is protected but tags are not — a compromised maintainer pushes `v9.9.9-evil` from a feature branch and the publish workflow ships it.",
282
+ "implicated_controls": [
283
+ "nist-800-53-SR-3",
284
+ "nist-800-218-PW-4",
285
+ "iso-27001-2022-A.8.32"
286
+ ]
287
+ },
288
+ {
289
+ "pattern_id": "static-npm-token-instead-of-oidc",
290
+ "claim": "We use scoped, time-bound publishing credentials.",
291
+ "fast_detection_test": "Read the release workflow. Confirm publishing uses GitHub Actions OIDC (`id-token: write` + Trusted Publisher configured on the registry side: npm Trusted Publisher, PyPI Trusted Publisher, crates.io Trusted Publisher). Theater if the workflow references `secrets.NPM_TOKEN` / `secrets.PYPI_TOKEN` / `secrets.CARGO_TOKEN` — these are long-lived, broadly-scoped, leak-on-disclosure secrets. Cross-check: list the repo's stored secrets via gh CLI; if NPM_TOKEN exists, the workflow is one log-exfil away from publisher takeover.",
292
+ "implicated_controls": [
293
+ "nist-800-53-IA-5",
294
+ "nist-800-218-PO-3",
295
+ "slsa-l3"
296
+ ]
297
+ },
298
+ {
299
+ "pattern_id": "skill-or-plugin-signed-but-verification-not-gated",
300
+ "claim": "Our AI skills / plugins / extensions are Ed25519-signed for tamper-evidence.",
301
+ "fast_detection_test": "Inspect the publish workflow. If signing occurs (e.g. `node lib/sign.js sign-all` for Ed25519, or `cosign sign-blob` for sigstore), verify a verification step (`node lib/verify.js` / `cosign verify-blob`) gates the publish step in the SAME workflow run, with `if: failure() || cancelled()` not catching it. Theater if signing happens in one workflow run and verification in a separate one — there's a gap where an unsigned or wrong-signed artifact can be published if the verification workflow is broken or skipped.",
302
+ "implicated_controls": [
303
+ "nist-800-53-SR-4",
304
+ "nist-800-218-PW-4",
305
+ "openssf-model-signing"
306
+ ]
307
+ },
308
+ {
309
+ "pattern_id": "vex-claimed-but-no-vex-feed-published",
310
+ "claim": "We respond to vulnerability reports filed against our product.",
311
+ "fast_detection_test": "Look for a published VEX feed: a stable URL serving CSAF 2.0 VEX documents, GitHub Security Advisories with VEX justifications, or a `vex.json` / `*.vex.cdx.json` artifact in the release. Cross-reference against the most recent CVE filed against the product (search NVD / GHSA for the product name). Theater if a CVE is filed and no VEX statement exists declaring not_affected / affected / fixed / under_investigation — downstream SBOM-scanning consumers cannot tell whether the CVE applies to their use of the product.",
312
+ "implicated_controls": [
313
+ "nist-800-218-RV-2",
314
+ "vex-csaf-2-1",
315
+ "eu-cra-art14"
316
+ ]
317
+ },
318
+ {
319
+ "pattern_id": "no-security-txt-no-disclosure-path",
320
+ "claim": "We follow coordinated vulnerability disclosure (ISO 29147 / 30111).",
321
+ "fast_detection_test": "Confirm (a) `/.well-known/security.txt` is served from the product's primary domain with valid Contact + Expires + Encryption fields, (b) `SECURITY.md` or `.github/SECURITY.md` is present in the repo with a documented disclosure path + response SLA, (c) the product has a published PGP key OR an OIDC-authenticated disclosure intake (e.g. GitHub private vulnerability reporting enabled). Theater if any of these are absent — there is no machine-discoverable disclosure path, and security researchers will either disclose publicly or not disclose at all.",
322
+ "implicated_controls": [
323
+ "nist-800-218-RV-1",
324
+ "iso-29147",
325
+ "iso-30111",
326
+ "eu-cra-art13"
327
+ ]
328
+ },
329
+ {
330
+ "pattern_id": "vendored-deps-without-provenance",
331
+ "claim": "We vendor selected dependencies for reproducibility.",
332
+ "fast_detection_test": "Walk `vendor/` (or `third_party/`, `external/`, `node_modules/` if vendored). For each vendored directory: locate the upstream source (commit SHA, release tag, sha256 of source archive) recorded in a manifest (e.g. `vendor.json`, `go.mod` vendored mode, `Cargo.lock` with `[[patch]]`, an explicit `THIRD_PARTY_PROVENANCE.md`). Theater if vendored code is present but provenance manifest is missing — there is no machine-verifiable claim about what's bundled, and divergence from upstream (intentional patches or malicious modifications) cannot be detected without a full source-diff.",
333
+ "implicated_controls": [
334
+ "nist-800-53-SR-4",
335
+ "nist-800-218-PS-3",
336
+ "slsa-l2"
337
+ ]
338
+ },
339
+ {
340
+ "pattern_id": "ssdf-compliant-but-not-cra-ready",
341
+ "claim": "We meet NIST 800-218 SSDF — we're CRA-ready.",
342
+ "fast_detection_test": "Compare current SSDF posture against EU CRA Annex I requirements that go beyond SSDF: (a) Art.10 five-year security update obligation with documented support lifecycle, (b) Art.13 conformity-assessment for Class II products, (c) Art.14 24-hour notification of actively-exploited vulnerabilities with CSAF advisory, (d) signed SBOM distributed with the product (SSDF mandates generation, not signing or distribution), (e) Annex I §3 vulnerability-handling procedure with documented disclosure intake. Theater if SSDF compliance is asserted as CRA-readiness — SSDF is implementable today, CRA is binding from 2027 with stricter Annex I content.",
343
+ "implicated_controls": [
344
+ "nist-800-218-PS-3",
345
+ "eu-cra-art10",
346
+ "eu-cra-art13",
347
+ "eu-cra-art14"
348
+ ]
349
+ }
350
+ ],
351
+ "framework_context": {
352
+ "gap_summary": "Library / framework / SDK publishers occupy the upstream side of the supply chain — every weakness in their release pipeline becomes a weakness in every downstream consumer. Current frameworks (NIST 800-53 SR-3/4/5, NIST 800-218 SSDF, ISO 27001:2022 A.8.30/A.5.20, SOC 2 CC9.x, NIS2 Art.21(2)(d), DORA Art.28) treat the publisher as a 'supplier' rather than as a control surface. NIST SSDF (PS.3.2) mandates SBOM generation but says nothing about signing, distribution, transitive completeness, or VEX issuance — exactly the gaps EU CRA Art.13/14 closes from 2027. The structural lag therefore has two layers: (1) operational tooling (Sigstore, in-toto, SLSA, CycloneDX VEX, npm/PyPI/crates Trusted Publisher OIDC) shipped in 2023-2025 and is broadly available; (2) compliance frameworks are 18+ months behind binding it, with CRA implementing acts arriving 2026-2027. The XZ Utils backdoor (CVE-2024-3094, 2024) is the canonical demonstration that maintainer-position long-game compromise — possible because the publisher's release signing was a personal key on a personal machine — bypasses every framework control that doesn't require OIDC publish, transparency-log attestation, and reproducible builds. Publishers of AI tools (skills, MCP servers, plugin packages) add an additional layer: skill / plugin signatures must be verified at install time, not just at publish time, and the verification step must gate the install — CVE-2026-30615 (Windsurf MCP zero-interaction RCE) is the canonical demonstration of what happens when that gate is missing.",
353
+ "lag_score": 540,
354
+ "per_framework_gaps": [
355
+ {
356
+ "framework": "nist-800-53",
357
+ "control_id": "SR-3",
358
+ "designed_for": "Supply chain controls and processes.",
359
+ "insufficient_because": "Procurement-event lens; does not require continuous attestation of every release artifact's provenance to an immutable transparency log."
360
+ },
361
+ {
362
+ "framework": "nist-800-53",
363
+ "control_id": "SR-4",
364
+ "designed_for": "Provenance.",
365
+ "insufficient_because": "Names provenance as a control; does not bind in-toto / SLSA / Sigstore as required attestation formats. Implementation-defined leaves room for theater (a README that says 'we sign releases')."
366
+ },
367
+ {
368
+ "framework": "nist-800-53",
369
+ "control_id": "SR-5",
370
+ "designed_for": "Acquisition strategies, tools, and methods.",
371
+ "insufficient_because": "Acquirer-side lens. The publisher acquiring its own dependencies needs the same controls; SR-5 doesn't say so."
372
+ },
373
+ {
374
+ "framework": "nist-800-218",
375
+ "control_id": "PS.3.2",
376
+ "designed_for": "Archive and protect each software release; produce SBOM.",
377
+ "insufficient_because": "Mandates SBOM production; does NOT require (a) signing, (b) distribution with the product, (c) transitive completeness, (d) VEX issuance, (e) OIDC-based publish, (f) Rekor / transparency log entry per release."
378
+ },
379
+ {
380
+ "framework": "nist-800-218",
381
+ "control_id": "PW.4",
382
+ "designed_for": "Reuse existing, well-secured software components.",
383
+ "insufficient_because": "Reuse lens; does not address what the publisher's own pipeline must do to BE that well-secured component for downstream."
384
+ },
385
+ {
386
+ "framework": "nist-800-218",
387
+ "control_id": "RV.2",
388
+ "designed_for": "Assess, prioritize, and remediate vulnerabilities.",
389
+ "insufficient_because": "Does not require VEX issuance — downstream consumers cannot tell whether a CVE filed against the publisher's product applies to their use of it."
390
+ },
391
+ {
392
+ "framework": "iso-27001-2022",
393
+ "control_id": "A.8.30",
394
+ "designed_for": "Outsourced development.",
395
+ "insufficient_because": "Outsourcing lens. A library author IS the outsourced developer for thousands of consumers; A.8.30 doesn't address what they must do."
396
+ },
397
+ {
398
+ "framework": "iso-27001-2022",
399
+ "control_id": "A.5.20",
400
+ "designed_for": "Information security in supplier agreements.",
401
+ "insufficient_because": "Contractual lens. Open-source library publishers have no supplier agreement with consumers; A.5.20 doesn't bind them."
402
+ },
403
+ {
404
+ "framework": "soc2",
405
+ "control_id": "CC8.1",
406
+ "designed_for": "Change management.",
407
+ "insufficient_because": "Internal-change lens. Doesn't require that publish artifacts carry transparency-log entries or that publish keys are OIDC-issued."
408
+ },
409
+ {
410
+ "framework": "soc2",
411
+ "control_id": "CC9.2",
412
+ "designed_for": "Vendor and business partner risk management.",
413
+ "insufficient_because": "Acquirer-side. Doesn't address the org's role as a publisher to others."
414
+ },
415
+ {
416
+ "framework": "nis2",
417
+ "control_id": "Art.21(2)(d)",
418
+ "designed_for": "Supply chain security, including security-related aspects of relationships with direct suppliers.",
419
+ "insufficient_because": "Names supply chain security; implementing acts have not bound publisher-side attestation requirements (OIDC publish, Rekor, VEX issuance, SBOM signing)."
420
+ },
421
+ {
422
+ "framework": "dora",
423
+ "control_id": "Art.28",
424
+ "designed_for": "ICT third-party risk management.",
425
+ "insufficient_because": "Contractual-ICT-third-party lens. Open-source dependency layer + AI-tool plugins are not contractual third parties; Art.28 doesn't capture them."
426
+ },
427
+ {
428
+ "framework": "eu-cra",
429
+ "control_id": "Art.10",
430
+ "designed_for": "Manufacturer's obligation to provide security updates throughout the product's expected use period (default 5 years).",
431
+ "insufficient_because": "Binds from 2027; until then, publishers have no compliance obligation to maintain a documented support lifecycle. Library authors who EOL packages without a security-update commitment create cliff exposure for downstream consumers."
432
+ },
433
+ {
434
+ "framework": "eu-cra",
435
+ "control_id": "Art.13 / Annex I",
436
+ "designed_for": "Essential cybersecurity requirements for products with digital elements; technical documentation including SBOM.",
437
+ "insufficient_because": "Binds 2027 with implementing acts in publication. Until then, SBOM format, signing requirement, and transitive completeness are not legally bound. CE marking + conformity assessment for Class II products is structurally new."
438
+ },
439
+ {
440
+ "framework": "eu-cra",
441
+ "control_id": "Art.14",
442
+ "designed_for": "24-hour notification of actively-exploited vulnerabilities to ENISA + national CSIRT.",
443
+ "insufficient_because": "Publishers without CSAF / advisory-pipeline tooling cannot meet the 24h notification window — they don't have the infrastructure to draft, sign, and distribute an advisory in time."
444
+ },
445
+ {
446
+ "framework": "uk-caf",
447
+ "control_id": "C1.b / B4.d",
448
+ "designed_for": "Supplier assurance and secure development.",
449
+ "insufficient_because": "Outcome-based; principle-level guidance with no binding attestation format. Implementers default to documentation-of-process over machine-verifiable attestation."
450
+ },
451
+ {
452
+ "framework": "au-essential-8",
453
+ "control_id": "E1 Application Control",
454
+ "designed_for": "Allow-list of approved applications.",
455
+ "insufficient_because": "Consumer-side lens. Doesn't bind the publisher to provide signed, attestable artifacts the consumer can verify against an allow-list."
456
+ },
457
+ {
458
+ "framework": "cmmc",
459
+ "control_id": "SI.L2-3.4.4",
460
+ "designed_for": "Configuration change control.",
461
+ "insufficient_because": "Internal-config lens. DIB publishers shipping artifacts to DoD-adjacent consumers need binding attestation, not change-control records."
462
+ }
463
+ ]
464
+ },
465
+ "skill_preload": [
466
+ "supply-chain-integrity",
467
+ "coordinated-vuln-disclosure",
468
+ "framework-gap-analysis",
469
+ "compliance-theater",
470
+ "policy-exception-gen",
471
+ "exploit-scoring"
472
+ ]
473
+ },
474
+ "direct": {
475
+ "threat_context": "Publisher-side supply-chain landscape Q1-Q2 2026: (1) XZ Utils backdoor (CVE-2024-3094, 2024) remains the load-bearing reference for maintainer-position long-game compromise — a trusted maintainer's release signing key on a personal laptop, no OIDC publish, no Rekor entry, no reproducible build = three-year infiltration. (2) PyPI typosquat + dependency-confusion campaigns continue to exploit publishers that lack namespace protection on internal package names (T1195.002). (3) GitHub Actions cache-poisoning (CVE family Q4-2025) demonstrates that workflow-mutable-by-PR runners can poison release pipelines unless `permissions: contents: read` is set at the workflow root and elevated only on protected events. (4) CVE-2026-30615 (Windsurf MCP zero-interaction RCE, 150M+ download blast radius) demonstrates the AI-tool publisher class: plugin / skill / extension publishers without enforced signature verification at install time hand attackers a developer-endpoint RCE. (5) The OpenSSF Scorecard initiative and Sigstore Trusted Publisher rollout (npm 2024-04, PyPI 2024-04, crates.io 2025-08) have made OIDC publish the new floor — publishers still on long-lived NPM_TOKEN / PYPI_TOKEN secrets are outside the moving baseline. (6) EU CRA Art.10/13/14 binding from 2027 forces publishers shipping products to the EU market into structural changes (5y support obligation, conformity assessment, 24h notification with CSAF advisory) that most are 12-18 months from being able to meet. Compliance trajectory: SSDF compliance today does NOT equal CRA-readiness; the gap is real and time-bound.",
476
+ "rwep_threshold": {
477
+ "escalate": 80,
478
+ "monitor": 50,
479
+ "close": 30
480
+ },
481
+ "framework_lag_declaration": "NIST 800-53 SR-3/4/5, NIST 800-218 SSDF PS.3.2 / PW.4 / RV.2, ISO 27001:2022 A.8.30 / A.5.20, SOC 2 CC8.1 / CC9.2, NIS2 Art.21(2)(d), DORA Art.28, UK CAF C1.b, AU Essential 8 E1, and CMMC SI.L2-3.4.4 all permit publisher posture that omits (a) OIDC-based publish, (b) Sigstore / Rekor transparency-log entries per release, (c) signed + distributed SBOM, (d) transitive completeness, (e) VEX feed for filed CVEs, (f) coordinated-disclosure intake at /.well-known/security.txt, (g) tag-protection on release refs, (h) reproducible builds, (i) skill / plugin signature verification gated in the install path. Operational tooling for (a)-(i) shipped 2023-2025; framework lag = ~540 days behind tooling and ~18 months ahead of EU CRA Art.10/13/14 binding (2027). Compensating controls MUST close (a)-(i) before SSDF-only compliance can be accepted as CRA-readiness.",
482
+ "skill_chain": [
483
+ {
484
+ "skill": "supply-chain-integrity",
485
+ "purpose": "Walk repo for release pipeline + published artifact + signing + provenance + SBOM + VEX posture. Cross-check claimed SLSA level against Rekor entries.",
486
+ "required": true
487
+ },
488
+ {
489
+ "skill": "coordinated-vuln-disclosure",
490
+ "purpose": "Test ISO 29147 / 30111 alignment: security.txt + SECURITY.md + CSAF advisory pipeline + private vulnerability reporting + 24h notification readiness.",
491
+ "required": true
492
+ },
493
+ {
494
+ "skill": "framework-gap-analysis",
495
+ "purpose": "Map publisher-posture gaps to framework controls insufficient to cover them (SR-3/4/5, SSDF, A.8.30, CC9, CRA Art.10/13/14).",
496
+ "skip_if": "analyze.framework_gap_mapping.length == 0",
497
+ "required": false
498
+ },
499
+ {
500
+ "skill": "compliance-theater",
501
+ "purpose": "Run the twelve publisher-side theater fingerprints in govern.theater_fingerprints.",
502
+ "required": true
503
+ },
504
+ {
505
+ "skill": "exploit-scoring",
506
+ "purpose": "For any CVE filed against the product or for matched vendored deps, compute RWEP using catalog kev / poc / ai-discovery / active-exploitation fields.",
507
+ "skip_if": "no_cves_filed_against_product AND no_matched_vendored_deps",
508
+ "required": false
509
+ },
510
+ {
511
+ "skill": "policy-exception-gen",
512
+ "purpose": "Generate auditor-ready exception language for publisher-posture gaps that cannot be remediated within the relevant compliance window (e.g. API stability promise prevents removing deprecated transitive dep).",
513
+ "skip_if": "close.exception_generation.trigger_condition == false",
514
+ "required": false
515
+ }
516
+ ],
517
+ "token_budget": {
518
+ "estimated_total": 28000,
519
+ "breakdown": {
520
+ "govern": 3400,
521
+ "direct": 1900,
522
+ "look": 3400,
523
+ "detect": 4200,
524
+ "analyze": 5800,
525
+ "validate": 5500,
526
+ "close": 3800
527
+ }
528
+ }
529
+ },
530
+ "look": {
531
+ "artifacts": [
532
+ {
533
+ "id": "release-workflows",
534
+ "type": "config_file",
535
+ "source": "Recursive read of .github/workflows/*.yml — primary focus on files matching release*, publish*, deploy*, cd*",
536
+ "description": "Release / publish pipeline definitions. Source of truth for OIDC vs static-token publishing, --provenance flag, pinned action SHAs, signing + verification gating.",
537
+ "required": true
538
+ },
539
+ {
540
+ "id": "package-manifest",
541
+ "type": "config_file",
542
+ "source": "package.json, pyproject.toml, Cargo.toml, *.gemspec, go.mod, composer.json, build.gradle, *.podspec",
543
+ "description": "Primary package manifest — publishConfig.provenance, publishConfig.access, files allow-list, bin entries, repository field, license, scripts (postinstall risk).",
544
+ "required": true
545
+ },
546
+ {
547
+ "id": "lockfiles",
548
+ "type": "config_file",
549
+ "source": "Recursive walk for: package-lock.json, yarn.lock, pnpm-lock.yaml, Pipfile.lock, poetry.lock, requirements*.txt with hashes, Cargo.lock, go.sum, Gemfile.lock, composer.lock, gradle.lockfile",
550
+ "description": "Lockfiles for the publisher's OWN build — pinning depth + integrity hashes. Determines whether the release pipeline is reproducible.",
551
+ "required": false
552
+ },
553
+ {
554
+ "id": "security-md",
555
+ "type": "config_file",
556
+ "source": "SECURITY.md, .github/SECURITY.md, docs/SECURITY.md",
557
+ "description": "Coordinated vulnerability disclosure intake documentation.",
558
+ "required": false
559
+ },
560
+ {
561
+ "id": "security-txt",
562
+ "type": "api_response",
563
+ "source": "If product has a primary domain: HTTP GET https://${domain}/.well-known/security.txt (network mode); else mark absent.",
564
+ "description": "RFC 9116 machine-discoverable disclosure path.",
565
+ "required": false,
566
+ "air_gap_alternative": "Skip in air-gap mode; mark inconclusive with low confidence impact."
567
+ },
568
+ {
569
+ "id": "signing-key-material",
570
+ "type": "file_path",
571
+ "source": "Locate: cosign.pub, *.pem (public-key signing artifacts), keys/public.pem, .well-known/openpgpkey/, sigstore-cosign metadata in workflow",
572
+ "description": "Public signing material committed to the repo or referenced from the release workflow.",
573
+ "required": false
574
+ },
575
+ {
576
+ "id": "intoto-attestations",
577
+ "type": "file_path",
578
+ "source": "Glob: *.intoto.jsonl, *.sigstore, *.sbom.json.sig, *.cdx.json.sig, attestations directory; AND for npm packages: GET https://registry.npmjs.org/${pkg} and inspect dist.attestations",
579
+ "description": "in-toto / Sigstore / SLSA provenance attestations attached to releases.",
580
+ "required": false,
581
+ "air_gap_alternative": "Network attestation fetch skipped; use only on-disk artifacts."
582
+ },
583
+ {
584
+ "id": "sbom-artifacts",
585
+ "type": "config_file",
586
+ "source": "Glob: *.cdx.json, *.spdx.json, bom.json, sbom.json, *.cyclonedx.json, *.spdx",
587
+ "description": "Existing SBOM artifacts for the published product.",
588
+ "required": false
589
+ },
590
+ {
591
+ "id": "vex-feed",
592
+ "type": "config_file",
593
+ "source": "Glob: *.vex.json, *.csaf.json, vex/, advisories/, .csaf/, *.openvex.json",
594
+ "description": "VEX statements / CSAF advisories the publisher issues about CVEs in their product.",
595
+ "required": false
596
+ },
597
+ {
598
+ "id": "vendored-code",
599
+ "type": "file_path",
600
+ "source": "List directories: vendor/, third_party/, external/, deps/, internal/vendor/; AND for each: locate provenance manifest (vendor.json, THIRD_PARTY_PROVENANCE.md, modules.txt for Go vendored)",
601
+ "description": "Vendored / bundled third-party code carried in the publisher's own release.",
602
+ "required": false
603
+ },
604
+ {
605
+ "id": "release-history",
606
+ "type": "config_file",
607
+ "source": "git tag --list 'v*' --sort=-creatordate | head -20; for each tag: git tag -v <tag> 2>&1 (signature verification); git for-each-ref --format='%(taggerdate) %(taggername) %(refname)' refs/tags/",
608
+ "description": "Most recent 20 release tags with signature status + tagger identity.",
609
+ "required": false
610
+ },
611
+ {
612
+ "id": "branch-tag-protection",
613
+ "type": "api_response",
614
+ "source": "If gh CLI available: gh api repos/${owner}/${repo}/branches/main/protection AND gh api repos/${owner}/${repo}/rules/branches AND gh api repos/${owner}/${repo}/tags/protection",
615
+ "description": "Branch + tag protection rules.",
616
+ "required": false,
617
+ "air_gap_alternative": "Mark inconclusive; rely on workflow YAML evidence of trigger restrictions."
618
+ },
619
+ {
620
+ "id": "repo-secrets",
621
+ "type": "api_response",
622
+ "source": "If gh CLI available: gh secret list --json name,visibility,updatedAt; AND gh secret list --env production --json name; check for NPM_TOKEN / PYPI_TOKEN / CARGO_TOKEN / RUBYGEMS_TOKEN long-lived publish credentials",
623
+ "description": "Repository-level secrets — presence of long-lived publish tokens is a fingerprint for non-OIDC publishing.",
624
+ "required": false,
625
+ "air_gap_alternative": "Mark inconclusive; rely on workflow YAML evidence."
626
+ },
627
+ {
628
+ "id": "release-checklist",
629
+ "type": "config_file",
630
+ "source": "RELEASE.md, docs/RELEASE.md, .github/RELEASE.md, .github/PULL_REQUEST_TEMPLATE/release.md",
631
+ "description": "Documented release checklist (informs whether disclosure / VEX / SBOM steps are even part of the manual process).",
632
+ "required": false
633
+ },
634
+ {
635
+ "id": "changelog",
636
+ "type": "config_file",
637
+ "source": "CHANGELOG.md, HISTORY.md, RELEASES.md, NEWS, docs/CHANGELOG.md",
638
+ "description": "Changelog — used to confirm whether security entries are tagged + cross-referenced to CVEs / advisories.",
639
+ "required": false
640
+ },
641
+ {
642
+ "id": "github-security-advisories",
643
+ "type": "api_response",
644
+ "source": "If gh CLI available: gh api repos/${owner}/${repo}/security-advisories; AND check repo settings: gh api repos/${owner}/${repo} --jq '.security_and_analysis'",
645
+ "description": "GitHub Security Advisories published by the project + private-vulnerability-reporting toggle status.",
646
+ "required": false,
647
+ "air_gap_alternative": "Mark inconclusive."
648
+ },
649
+ {
650
+ "id": "skill-signing-infrastructure",
651
+ "type": "file_path",
652
+ "source": "If repo ships skills / plugins / extensions: locate lib/sign.js, lib/verify.js, scripts/sign-skills.*, signatures/, keys/, AND read package.json scripts for sign/verify entries",
653
+ "description": "Specific to AI-tool / plugin / skill publishers: Ed25519 / cosign signing scaffolding.",
654
+ "required": false
655
+ },
656
+ {
657
+ "id": "registry-publisher-config",
658
+ "type": "api_response",
659
+ "source": "For npm: GET https://registry.npmjs.org/${pkg} and inspect maintainers + dist.attestations + dist.signatures; for PyPI: GET https://pypi.org/pypi/${pkg}/json and inspect attestations URL; for crates: GET https://crates.io/api/v1/crates/${pkg} and inspect trustpub status",
660
+ "description": "Registry-side publisher posture: Trusted Publisher enabled, 2FA on maintainer accounts, attestations attached.",
661
+ "required": false,
662
+ "air_gap_alternative": "Skip; rely on local workflow evidence."
663
+ }
664
+ ],
665
+ "collection_scope": {
666
+ "time_window": "current",
667
+ "asset_scope": "publisher_repo_and_release_pipeline",
668
+ "depth": "deep",
669
+ "sampling": "Repo-rooted walk + most-recent-20-releases inspection. Multi-package repos require per-package execution. Monorepo support: detect Nx / Lerna / pnpm-workspaces and iterate per published package."
670
+ },
671
+ "environment_assumptions": [
672
+ {
673
+ "assumption": "cwd is the root of a git repo that publishes artifacts",
674
+ "if_false": "Return visibility_gap=not_a_publisher_repo; this playbook does not apply. Internal-only repos route to `secrets` and `sbom` instead."
675
+ },
676
+ {
677
+ "assumption": "agent has read access to .github/, source manifests, lockfiles",
678
+ "if_false": "Halt — without workflow + manifest visibility, theater fingerprints cannot be tested."
679
+ },
680
+ {
681
+ "assumption": "gh CLI authenticated for the repo OR public-repo metadata reachable via network",
682
+ "if_false": "Mark branch/tag protection + repo secrets + security advisories inconclusive; downgrade theater fingerprint confidence for #6, #7, #9."
683
+ }
684
+ ],
685
+ "fallback_if_unavailable": [
686
+ {
687
+ "artifact_id": "release-workflows",
688
+ "fallback_action": "escalate_to_human",
689
+ "confidence_impact": "high"
690
+ },
691
+ {
692
+ "artifact_id": "package-manifest",
693
+ "fallback_action": "escalate_to_human",
694
+ "confidence_impact": "high"
695
+ },
696
+ {
697
+ "artifact_id": "lockfiles",
698
+ "fallback_action": "mark_inconclusive",
699
+ "confidence_impact": "medium"
700
+ },
701
+ {
702
+ "artifact_id": "security-md",
703
+ "fallback_action": "mark_inconclusive",
704
+ "confidence_impact": "low"
705
+ },
706
+ {
707
+ "artifact_id": "security-txt",
708
+ "fallback_action": "mark_inconclusive",
709
+ "confidence_impact": "low"
710
+ },
711
+ {
712
+ "artifact_id": "intoto-attestations",
713
+ "fallback_action": "mark_inconclusive",
714
+ "confidence_impact": "medium"
715
+ },
716
+ {
717
+ "artifact_id": "sbom-artifacts",
718
+ "fallback_action": "mark_inconclusive",
719
+ "confidence_impact": "medium"
720
+ },
721
+ {
722
+ "artifact_id": "vex-feed",
723
+ "fallback_action": "mark_inconclusive",
724
+ "confidence_impact": "medium"
725
+ },
726
+ {
727
+ "artifact_id": "vendored-code",
728
+ "fallback_action": "use_compensating_artifact",
729
+ "confidence_impact": "low"
730
+ },
731
+ {
732
+ "artifact_id": "branch-tag-protection",
733
+ "fallback_action": "mark_inconclusive",
734
+ "confidence_impact": "medium"
735
+ },
736
+ {
737
+ "artifact_id": "repo-secrets",
738
+ "fallback_action": "mark_inconclusive",
739
+ "confidence_impact": "medium"
740
+ },
741
+ {
742
+ "artifact_id": "registry-publisher-config",
743
+ "fallback_action": "mark_inconclusive",
744
+ "confidence_impact": "low"
745
+ },
746
+ {
747
+ "artifact_id": "skill-signing-infrastructure",
748
+ "fallback_action": "mark_inconclusive",
749
+ "confidence_impact": "low"
750
+ }
751
+ ]
752
+ },
753
+ "detect": {
754
+ "indicators": [
755
+ {
756
+ "id": "publish-workflow-uses-static-token",
757
+ "type": "file_path",
758
+ "value": "Any .github/workflows/*.yml publish/release job references secrets.NPM_TOKEN / secrets.PYPI_TOKEN / secrets.CARGO_TOKEN / secrets.RUBYGEMS_API_KEY / secrets.GEM_HOST_API_KEY without an OIDC alternative path",
759
+ "description": "Long-lived publisher credential — fingerprint for non-OIDC publishing (theater #7).",
760
+ "confidence": "deterministic",
761
+ "deterministic": true,
762
+ "attack_ref": "T1195.002"
763
+ },
764
+ {
765
+ "id": "publish-workflow-no-id-token-write",
766
+ "type": "file_path",
767
+ "value": "Publish/release job lacks permissions.id-token: write AND lacks Trusted Publisher configuration",
768
+ "description": "Cannot use Sigstore keyless or registry Trusted Publisher — OIDC publish is structurally unavailable.",
769
+ "confidence": "deterministic",
770
+ "deterministic": true
771
+ },
772
+ {
773
+ "id": "publish-workflow-action-refs-mutable",
774
+ "type": "file_path",
775
+ "value": "Any uses: in the publish/release workflow references a tag or branch (e.g. @v4, @main) rather than a 40-char SHA",
776
+ "description": "Mutable action reference — upstream owner can substitute action code under the same tag.",
777
+ "confidence": "deterministic",
778
+ "deterministic": true,
779
+ "attack_ref": "T1195.001"
780
+ },
781
+ {
782
+ "id": "package-json-provenance-missing",
783
+ "type": "file_path",
784
+ "value": "For npm publishers: package.json has no publishConfig.provenance == true AND publish workflow command does not carry --provenance",
785
+ "description": "npm provenance not enabled — no dist.attestations on the published package (theater #2).",
786
+ "confidence": "deterministic",
787
+ "deterministic": true
788
+ },
789
+ {
790
+ "id": "release-workflow-non-frozen-install",
791
+ "type": "file_path",
792
+ "value": "Release workflow uses `npm install` / `pnpm install` / `pip install -r` / `bundle install` (not the --frozen / --locked / --require-hashes variant) before the build step",
793
+ "description": "Mid-build dependency resolution — release artifact is not reproducible (theater #5).",
794
+ "confidence": "high",
795
+ "deterministic": false
796
+ },
797
+ {
798
+ "id": "lockfile-missing-integrity",
799
+ "type": "file_path",
800
+ "value": "Any pinned entry in walked lockfiles lacks an integrity field (sha512/sha384/sha256, sri-integrity, go.sum h1: hash)",
801
+ "description": "Name-pin only — vulnerable to publisher-key compromise re-publication-over.",
802
+ "confidence": "deterministic",
803
+ "deterministic": true
804
+ },
805
+ {
806
+ "id": "sbom-absent-or-unsigned",
807
+ "type": "file_path",
808
+ "value": "No SBOM artifact present in repo OR most-recent-release SBOM is present but no matching .sig / .sigstore / *.intoto.jsonl signature artifact",
809
+ "description": "SBOM theater #1 — present but unsigned, OR absent entirely.",
810
+ "confidence": "deterministic",
811
+ "deterministic": true,
812
+ "atlas_ref": "AML.T0010"
813
+ },
814
+ {
815
+ "id": "sbom-regenerated-at-request-time",
816
+ "type": "behavioral_signal",
817
+ "value": "SBOM generation script exists in repo (e.g. scripts/generate-sbom.*) but no SBOM artifact is committed AND no release-workflow step uploads an SBOM to release assets",
818
+ "description": "SBOM-on-demand — historical releases have no immutable SBOM.",
819
+ "confidence": "high",
820
+ "deterministic": false
821
+ },
822
+ {
823
+ "id": "no-rekor-entry-for-latest-release",
824
+ "type": "behavioral_signal",
825
+ "value": "Network mode: rekor-cli search by sha256 of latest release artifact returns empty AND project README/docs claim SLSA L3 or higher",
826
+ "description": "SLSA-claim-without-attestation (theater #4).",
827
+ "confidence": "high",
828
+ "deterministic": false
829
+ },
830
+ {
831
+ "id": "tag-protection-absent",
832
+ "type": "api_response",
833
+ "value": "gh api repos/${owner}/${repo}/tags/protection returns empty array OR 404 AND publish workflow triggers on push tags: ['v*']",
834
+ "description": "Release tags unprotected (theater #6) — any branch can push v* and trigger publish.",
835
+ "confidence": "deterministic",
836
+ "deterministic": true
837
+ },
838
+ {
839
+ "id": "release-tag-not-signed",
840
+ "type": "behavioral_signal",
841
+ "value": "git tag -v <latest_release_tag> returns 'no signature found' OR signature does not verify",
842
+ "description": "Tag-signing absent — release authenticity rests on push-time access control only.",
843
+ "confidence": "deterministic",
844
+ "deterministic": true
845
+ },
846
+ {
847
+ "id": "release-signed-with-personal-gpg-key",
848
+ "type": "behavioral_signal",
849
+ "value": "Tag signature verifies against a PGP key whose UID is a personal email (not an org / project address) AND key is not registered in Sigstore Rekor / Web Key Directory",
850
+ "description": "Personal-laptop signing key (theater #3) — XZ-class compromise vector.",
851
+ "confidence": "high",
852
+ "deterministic": false
853
+ },
854
+ {
855
+ "id": "no-security-md",
856
+ "type": "file_path",
857
+ "value": "Absence of SECURITY.md / .github/SECURITY.md / docs/SECURITY.md from the repo",
858
+ "description": "No documented disclosure path (theater #10).",
859
+ "confidence": "deterministic",
860
+ "deterministic": true
861
+ },
862
+ {
863
+ "id": "no-security-txt",
864
+ "type": "api_response",
865
+ "value": "If product has a primary domain: HTTP 404 / connection failure on /.well-known/security.txt",
866
+ "description": "No RFC 9116 machine-discoverable disclosure path (theater #10).",
867
+ "confidence": "deterministic",
868
+ "deterministic": true
869
+ },
870
+ {
871
+ "id": "private-vuln-reporting-disabled",
872
+ "type": "api_response",
873
+ "value": "gh api repos/${owner}/${repo} --jq '.security_and_analysis.private_vulnerability_reporting.status' returns 'disabled'",
874
+ "description": "GitHub private vulnerability reporting off — no OIDC-authenticated disclosure intake.",
875
+ "confidence": "deterministic",
876
+ "deterministic": true
877
+ },
878
+ {
879
+ "id": "vex-feed-absent",
880
+ "type": "file_path",
881
+ "value": "Absence of vex/, *.vex.json, *.csaf.json, *.openvex.json AND project has at least one published GitHub Security Advisory OR at least one filed CVE in NVD",
882
+ "description": "VEX issuance gap (theater #9) — CVEs filed against the product, no machine-readable exploitability declaration.",
883
+ "confidence": "deterministic",
884
+ "deterministic": true
885
+ },
886
+ {
887
+ "id": "vendored-no-provenance",
888
+ "type": "file_path",
889
+ "value": "vendor/ or third_party/ directories present AND no provenance manifest (vendor.json, THIRD_PARTY_PROVENANCE.md, modules.txt) AND not a Go vendored module",
890
+ "description": "Vendored code without machine-verifiable upstream provenance (theater #11).",
891
+ "confidence": "deterministic",
892
+ "deterministic": true
893
+ },
894
+ {
895
+ "id": "skill-signing-but-verification-not-gated",
896
+ "type": "file_path",
897
+ "value": "Repo contains skill / plugin signing infrastructure (sign.js / cosign sign-blob in workflow) AND verify step exists in a separate workflow OR is conditionally skipped on the publish workflow",
898
+ "description": "Signing-without-gating (theater #8) — AI-tool publisher fingerprint.",
899
+ "confidence": "high",
900
+ "deterministic": false
901
+ },
902
+ {
903
+ "id": "ssdf-claimed-cra-not-ready",
904
+ "type": "behavioral_signal",
905
+ "value": "README / docs / SECURITY.md claim NIST SSDF compliance AND no five-year-support-commitment statement AND no CSAF advisory pipeline AND no signed-and-distributed SBOM",
906
+ "description": "SSDF-as-CRA-readiness theater (theater #12).",
907
+ "confidence": "high",
908
+ "deterministic": false
909
+ },
910
+ {
911
+ "id": "publish-workflow-runs-on-self-hosted",
912
+ "type": "file_path",
913
+ "value": "Publish/release job runs-on includes 'self-hosted' OR a non-GitHub-hosted ephemeral runner",
914
+ "description": "Self-hosted runner — persistent runner state can be poisoned across runs.",
915
+ "confidence": "high",
916
+ "deterministic": false
917
+ }
918
+ ],
919
+ "false_positive_profile": [
920
+ {
921
+ "indicator_id": "publish-workflow-uses-static-token",
922
+ "benign_pattern": "Registry does not yet support Trusted Publisher / OIDC (e.g. some private registries, older artifact repos).",
923
+ "distinguishing_test": "Check registry capability: npm / PyPI / crates / RubyGems all support OIDC since 2024-04, 2024-04, 2025-08, 2025-02 respectively. Private registries (Artifactory, Verdaccio, Nexus) may not — confirm the registry is private and OIDC is genuinely unavailable. If so, downgrade to medium and recommend short-lived token rotation + scope minimization."
924
+ },
925
+ {
926
+ "indicator_id": "publish-workflow-action-refs-mutable",
927
+ "benign_pattern": "GitHub-authored actions (actions/checkout, actions/setup-node) under the actions/ org are commonly pinned by major version with org-level supply-chain guarantees.",
928
+ "distinguishing_test": "Distinguish actions/ org (Allow) from third-party orgs (Block) — GitHub-authored actions pinned by major version are accepted by SLSA / OpenSSF guidance; third-party action references MUST be SHA-pinned per OpenSSF Scorecard."
929
+ },
930
+ {
931
+ "indicator_id": "release-signed-with-personal-gpg-key",
932
+ "benign_pattern": "Long-established maintainer with a well-known PGP key registered in the Web Key Directory for the project's domain (key UID matches @project-domain.org, key is in WKD at the project's well-known URL).",
933
+ "distinguishing_test": "Look up the project's WKD: curl https://${project_domain}/.well-known/openpgpkey/hu/${wkd_hash} — if the key resolves AND the UID matches a project-domain address, downgrade to medium with rotation-cadence note. If the UID is a free-mail address (gmail / proton / outlook), retain as high-confidence personal-laptop-key fingerprint."
934
+ },
935
+ {
936
+ "indicator_id": "vex-feed-absent",
937
+ "benign_pattern": "Project is too new to have had a CVE filed against it.",
938
+ "distinguishing_test": "Cross-check NVD / GHSA / OSV.dev for any CVE / advisory naming the project. If zero results AND project has < 100 stars AND < 6 months since first release, downgrade to low and recommend proactive VEX tooling adoption. Otherwise retain."
939
+ },
940
+ {
941
+ "indicator_id": "no-security-md",
942
+ "benign_pattern": "Org-level SECURITY.md inherited via GitHub's .github org repo applies to all repos in the org.",
943
+ "distinguishing_test": "Check ${owner}/.github repo for a top-level SECURITY.md — GitHub's UI inherits this. If present and current, downgrade to low and recommend repo-local override only if disclosure path differs."
944
+ },
945
+ {
946
+ "indicator_id": "vendored-no-provenance",
947
+ "benign_pattern": "Go modules using `go mod vendor` produce a deterministic vendor/modules.txt that IS the provenance manifest.",
948
+ "distinguishing_test": "If vendor/modules.txt exists and the project uses Go, this is provenance-present. Do not flag."
949
+ }
950
+ ],
951
+ "minimum_signal": {
952
+ "detected": "Any of: (a) publish-workflow-uses-static-token=true, (b) tag-protection-absent=true AND publish triggers on tags, (c) sbom-absent-or-unsigned=true, (d) no-security-md=true AND no-security-txt=true (combined disclosure absence), (e) vex-feed-absent=true with filed CVEs, (f) skill-signing-but-verification-not-gated=true (for AI-tool publishers), (g) no-rekor-entry-for-latest-release=true with SLSA-L3+ claim, (h) release-signed-with-personal-gpg-key=true.",
953
+ "inconclusive": "Repo walk succeeded but network-mode artifacts (security-txt, rekor entries, registry-publisher-config, branch-tag-protection, security-advisories) unavailable; theater fingerprints #1, #4, #6, #9, #10 cannot be tested. Confidence on detected signals retained; absence-of-detection cannot be asserted.",
954
+ "not_detected": "All twelve theater fingerprints test negative AND no indicator fires AND a successful Rekor verify exists for the most recent release artifact AND VEX feed is published AND security.txt + SECURITY.md + private vulnerability reporting all present AND tag protection enforced AND OIDC publish in place AND lockfiles integrity-pinned AND SBOM signed + distributed AND vendored code provenance-manifested."
955
+ }
956
+ },
957
+ "analyze": {
958
+ "rwep_inputs": [
959
+ {
960
+ "signal_id": "publish-workflow-uses-static-token",
961
+ "rwep_factor": "blast_radius",
962
+ "weight": 20,
963
+ "notes": "Token leak = publisher-position takeover. Blast radius scales with downstream consumer count."
964
+ },
965
+ {
966
+ "signal_id": "publish-workflow-no-id-token-write",
967
+ "rwep_factor": "blast_radius",
968
+ "weight": 10,
969
+ "notes": "Structurally cannot use OIDC; signals release-pipeline modernization gap."
970
+ },
971
+ {
972
+ "signal_id": "publish-workflow-action-refs-mutable",
973
+ "rwep_factor": "active_exploitation",
974
+ "weight": 10,
975
+ "notes": "Upstream-substitution attacks against mutable action refs are operational (T1195.001)."
976
+ },
977
+ {
978
+ "signal_id": "tag-protection-absent",
979
+ "rwep_factor": "blast_radius",
980
+ "weight": 15,
981
+ "notes": "Any-branch v* push triggers publish — single compromised contributor account ships a malicious release."
982
+ },
983
+ {
984
+ "signal_id": "release-tag-not-signed",
985
+ "rwep_factor": "blast_radius",
986
+ "weight": 10,
987
+ "notes": "Authenticity rests on access control only — no out-of-band verification path."
988
+ },
989
+ {
990
+ "signal_id": "release-signed-with-personal-gpg-key",
991
+ "rwep_factor": "blast_radius",
992
+ "weight": 15,
993
+ "notes": "XZ-Utils-class fingerprint — personal-laptop key compromise = three-year infiltration."
994
+ },
995
+ {
996
+ "signal_id": "lockfile-missing-integrity",
997
+ "rwep_factor": "active_exploitation",
998
+ "weight": 5,
999
+ "notes": "Re-publication-over campaigns documented in 2024-2026."
1000
+ },
1001
+ {
1002
+ "signal_id": "sbom-absent-or-unsigned",
1003
+ "rwep_factor": "blast_radius",
1004
+ "weight": 10,
1005
+ "notes": "Downstream consumers cannot reliably correlate CVEs against the product — every consumer's CVE-match-time becomes manual."
1006
+ },
1007
+ {
1008
+ "signal_id": "vex-feed-absent",
1009
+ "rwep_factor": "blast_radius",
1010
+ "weight": 10,
1011
+ "notes": "Every downstream consumer's SBOM scanner alerts on the publisher's CVEs with no exploitability context."
1012
+ },
1013
+ {
1014
+ "signal_id": "no-rekor-entry-for-latest-release",
1015
+ "rwep_factor": "ai_weaponization",
1016
+ "weight": 5,
1017
+ "notes": "AI-discovered weaknesses in unverifiable builds are harder for downstream to triage; pairs with claim-vs-reality theater."
1018
+ },
1019
+ {
1020
+ "signal_id": "skill-signing-but-verification-not-gated",
1021
+ "rwep_factor": "active_exploitation",
1022
+ "weight": 15,
1023
+ "notes": "CVE-2026-30615 class — zero-interaction RCE via unverified plugin at install time."
1024
+ },
1025
+ {
1026
+ "signal_id": "no-security-md",
1027
+ "rwep_factor": "patch_available",
1028
+ "weight": -5,
1029
+ "notes": "Inverse — no disclosure path slows time-to-fix because researchers can't report; informational."
1030
+ },
1031
+ {
1032
+ "signal_id": "publish-workflow-runs-on-self-hosted",
1033
+ "rwep_factor": "active_exploitation",
1034
+ "weight": 10,
1035
+ "notes": "Self-hosted-runner-poisoning is operational TTP."
1036
+ }
1037
+ ],
1038
+ "blast_radius_model": {
1039
+ "scope_question": "If this publisher's release pipeline is compromised, what scope of downstream compromise does a single malicious release deliver?",
1040
+ "scoring_rubric": [
1041
+ {
1042
+ "condition": "internal-use-only library, single consumer org, < 10 downstream services, no public registry presence",
1043
+ "blast_radius_score": 1,
1044
+ "description": "Single-org blast — internal incident response."
1045
+ },
1046
+ {
1047
+ "condition": "public registry presence with < 10k weekly downloads OR < 50 dependents, no enterprise consumers documented",
1048
+ "blast_radius_score": 2,
1049
+ "description": "Niche library — manageable downstream notification list."
1050
+ },
1051
+ {
1052
+ "condition": "public registry presence with 10k-1M weekly downloads OR known enterprise consumers OR is a build-tool / linter / formatter in widespread CI use",
1053
+ "blast_radius_score": 3,
1054
+ "description": "Mid-tier library — meaningful downstream notification + remediation campaign."
1055
+ },
1056
+ {
1057
+ "condition": "framework / SDK with > 1M weekly downloads OR > 1000 dependents OR is a security-relevant dep (auth, crypto, parsing, serialization) OR is in transitive-dep position for major frameworks",
1058
+ "blast_radius_score": 4,
1059
+ "description": "Widely-distributed framework — XZ-class downstream propagation possible."
1060
+ },
1061
+ {
1062
+ "condition": "developer tooling installed on developer endpoints (IDE plugin, MCP server, AI assistant, CLI installed via pipe-to-shell), OR build-system bootstrap (npm itself, pip itself, cargo itself), OR > 100M downloads, OR is a transitive dep for build-time-execution surfaces",
1063
+ "blast_radius_score": 5,
1064
+ "description": "Developer-endpoint or build-bootstrap surface — CVE-2026-30615 / XZ Utils class. Zero-interaction RCE on developer endpoints; ecosystem-wide rebuild required."
1065
+ }
1066
+ ]
1067
+ },
1068
+ "compliance_theater_check": {
1069
+ "claim": "Our release pipeline follows secure-supply-chain best practices: NIST SSDF, SLSA, EU CRA Annex I, ISO 27001 A.8.30 / A.5.20 — and we publish SBOMs and sign releases.",
1070
+ "audit_evidence": "README / SECURITY.md / DPA / customer-facing trust portal naming SSDF / SLSA / CRA compliance; SBOM artifact in release assets; signing-step in release workflow; documented disclosure policy.",
1071
+ "reality_test": "Run all twelve theater fingerprints in govern.theater_fingerprints with concrete cross-checks: (1) cosign verify the most recent release artifact against the documented signing identity AND confirm Rekor entry exists; (2) GET https://registry.npmjs.org/${pkg} and inspect dist.attestations field — if empty, npm-provenance is documentation-only; (3) provenance.json should be fetchable via the registry API (npm: /-/npm/v1/security/audits/quick); (4) compare the lockfile commit referenced in the release tag against the lockfile referenced in the release workflow — must match for the build to be reproducible; (5) gh api repos/${owner}/${repo}/tags/protection — must be non-empty for v*; (6) `cosign verify --certificate-identity-regexp` against the publish workflow's OIDC identity — must match the org / repo / ref; (7) for each CVE filed against the product over the last 24 months, locate the VEX statement — must exist with not_affected / affected / fixed / under_investigation; (8) GET https://${product_domain}/.well-known/security.txt — must return 200 with valid Contact + Expires; (9) for AI-tool publishers (skills, plugins, MCP servers), confirm the signing step AND verification step are in the same workflow run, with verification gating the publish step; (10) confirm five-year-support-commitment in SECURITY.md or product trust portal — required by EU CRA Art.10 from 2027. Theater if any of (1)-(10) fails AND no compensating control with current test exists.",
1072
+ "theater_verdict_if_gap": "Publisher claims secure-supply-chain posture that nonetheless leaves the release pipeline (a) signable by a maintainer's personal laptop key, (b) publishable from any unprotected branch via tag push, (c) reproducible only on paper, (d) auditable only via an unsigned, regenerated-on-request SBOM, (e) unscoped against downstream consumers' CVE-correlation needs (no VEX), (f) unreachable for security researchers (no security.txt + no SECURITY.md + no GitHub private vuln reporting), (g) structurally unable to meet EU CRA Art.14's 24-hour notification window once binding in 2027. Either (i) wire OIDC publish + Sigstore signing + Rekor entry verification + tag protection + signed SBOM distribution + VEX feed + CSAF advisory pipeline + RFC 9116 security.txt + five-year-support-commitment + skill signature verification gate, (ii) generate a defensible policy exception via policy-exception-gen documenting that the API stability promise (or whatever blocker) prevents specific items with compensating controls + sunset date."
1073
+ },
1074
+ "framework_gap_mapping": [
1075
+ {
1076
+ "finding_id": "publisher-posture-gap",
1077
+ "framework": "nist-800-53",
1078
+ "claimed_control": "SR-3 — Supply Chain Controls and Processes",
1079
+ "actual_gap": "Procurement / acquirer lens. Does not bind publisher-side OIDC publish, Rekor entry per release, signed SBOM, VEX feed, RFC 9116 disclosure path.",
1080
+ "required_control": "SR-3 publisher-side variant requiring OIDC-based publish to a registry that supports Trusted Publisher, Sigstore Rekor entry per release artifact, signed CycloneDX 1.6 or SPDX 3.0 SBOM distributed with the release, VEX feed maintenance per filed CVE, RFC 9116 security.txt at primary product domain."
1081
+ },
1082
+ {
1083
+ "finding_id": "publisher-posture-gap",
1084
+ "framework": "nist-800-53",
1085
+ "claimed_control": "SR-4 — Provenance",
1086
+ "actual_gap": "Names provenance as a control; does not bind SLSA / in-toto / Sigstore as required attestation formats.",
1087
+ "required_control": "SR-4 update binding SLSA v1.0 Level 3 (or higher), in-toto attestation chain, Sigstore transparency-log entry as required provenance evidence formats."
1088
+ },
1089
+ {
1090
+ "finding_id": "publisher-posture-gap",
1091
+ "framework": "nist-800-218",
1092
+ "claimed_control": "PS.3.2 — Archive software releases, produce SBOM",
1093
+ "actual_gap": "SBOM generation only; no signing, distribution, transitive completeness, or VEX issuance requirement.",
1094
+ "required_control": "PS.3.2+ requiring signed SBOM distributed with every release, transitive-completeness check vs lockfile resolution, VEX issuance for every CVE filed against the product within 14 days."
1095
+ },
1096
+ {
1097
+ "finding_id": "publisher-posture-gap",
1098
+ "framework": "nist-800-218",
1099
+ "claimed_control": "PW.4 — Reuse existing, well-secured software",
1100
+ "actual_gap": "Reuse lens; does not address publisher-side disciplines that make the org BE the well-secured component for downstream.",
1101
+ "required_control": "PW.4 publisher-side variant requiring tag-protection on release refs, OIDC publish, pinned action SHAs, frozen-lockfile install in release pipeline."
1102
+ },
1103
+ {
1104
+ "finding_id": "publisher-posture-gap",
1105
+ "framework": "nist-800-218",
1106
+ "claimed_control": "RV.2 — Assess, prioritize, remediate vulnerabilities",
1107
+ "actual_gap": "No VEX issuance requirement — downstream consumers can't tell if a filed CVE applies to their use.",
1108
+ "required_control": "RV.2 update binding VEX issuance per filed CVE (CSAF 2.0 VEX profile), 24-hour notification on actively-exploited matches (aligned to EU CRA Art.14)."
1109
+ },
1110
+ {
1111
+ "finding_id": "publisher-posture-gap",
1112
+ "framework": "iso-27001-2022",
1113
+ "claimed_control": "A.8.30 — Outsourced development",
1114
+ "actual_gap": "Outsourcing lens. A library author IS the outsourced developer for downstream; A.8.30 doesn't address their publisher-side disciplines.",
1115
+ "required_control": "A.8.30 publisher-side annex binding OIDC publish + signed releases + VEX feed + RFC 9116 disclosure."
1116
+ },
1117
+ {
1118
+ "finding_id": "publisher-posture-gap",
1119
+ "framework": "iso-27001-2022",
1120
+ "claimed_control": "A.5.20 — Information security in supplier agreements",
1121
+ "actual_gap": "Contractual lens; open-source publishers have no supplier agreement with consumers.",
1122
+ "required_control": "A.5.20 amendment for community-maintained publishers binding technical attestation as substitute for contractual obligation."
1123
+ },
1124
+ {
1125
+ "finding_id": "publisher-posture-gap",
1126
+ "framework": "soc2",
1127
+ "claimed_control": "CC8.1 / CC9.2 — Change management + vendor risk",
1128
+ "actual_gap": "Internal-change / acquirer lens. Doesn't bind the org's role as publisher.",
1129
+ "required_control": "Trust Services Criteria amendment for change management of published artifacts (tag protection, OIDC publish, signature verification gate)."
1130
+ },
1131
+ {
1132
+ "finding_id": "publisher-posture-gap",
1133
+ "framework": "nis2",
1134
+ "claimed_control": "Art.21(2)(d) — Supply chain security",
1135
+ "actual_gap": "Implementing acts not yet bound to publisher-side attestation.",
1136
+ "required_control": "Implementing acts binding OIDC publish + Rekor entry + signed SBOM + VEX feed for essential entities publishing software."
1137
+ },
1138
+ {
1139
+ "finding_id": "publisher-posture-gap",
1140
+ "framework": "dora",
1141
+ "claimed_control": "Art.28 — ICT third-party risk",
1142
+ "actual_gap": "Contractual-third-party lens; open-source dependency layer + AI-tool plugins not captured.",
1143
+ "required_control": "RTS/ITS extending Art.28 to dependency layer with technical attestation substitute."
1144
+ },
1145
+ {
1146
+ "finding_id": "publisher-posture-gap",
1147
+ "framework": "eu-cra",
1148
+ "claimed_control": "Art.10 — Five-year security update obligation",
1149
+ "actual_gap": "Binds 2027. Until then, no compliance obligation to maintain documented support lifecycle.",
1150
+ "required_control": "Implementing act binding documented end-of-support timeline + security-update commitment per product."
1151
+ },
1152
+ {
1153
+ "finding_id": "publisher-posture-gap",
1154
+ "framework": "eu-cra",
1155
+ "claimed_control": "Art.13 / Annex I — Essential cybersecurity requirements + technical documentation",
1156
+ "actual_gap": "Binds 2027 with implementing acts in publication.",
1157
+ "required_control": "Implementing acts binding SBOM signing + distribution + transitive completeness + conformity assessment for Class II products."
1158
+ },
1159
+ {
1160
+ "finding_id": "publisher-posture-gap",
1161
+ "framework": "eu-cra",
1162
+ "claimed_control": "Art.14 — 24-hour notification of actively-exploited vulnerabilities",
1163
+ "actual_gap": "Publishers without CSAF advisory pipeline cannot meet the 24h window.",
1164
+ "required_control": "Operational guidance: pre-deployed CSAF advisory template + automated draft on match + ENISA single-reporting-platform integration."
1165
+ },
1166
+ {
1167
+ "finding_id": "publisher-posture-gap",
1168
+ "framework": "uk-caf",
1169
+ "claimed_control": "C1.b / B4.d — Supplier assurance and secure development",
1170
+ "actual_gap": "Outcome-based; no binding attestation format.",
1171
+ "required_control": "CAF profile binding Sigstore + SLSA L3 + signed SBOM + VEX as evidence of outcome."
1172
+ },
1173
+ {
1174
+ "finding_id": "publisher-posture-gap",
1175
+ "framework": "au-essential-8",
1176
+ "claimed_control": "E1 — Application Control",
1177
+ "actual_gap": "Consumer-side lens; doesn't bind publisher to provide attestable artifacts.",
1178
+ "required_control": "AU ISM update binding publisher-side attestation for software shipped to AU government / Critical Infrastructure consumers."
1179
+ },
1180
+ {
1181
+ "finding_id": "publisher-posture-gap",
1182
+ "framework": "cmmc",
1183
+ "claimed_control": "SI.L2-3.4.4 — Configuration change control",
1184
+ "actual_gap": "Internal-config lens; DIB publishers need binding attestation.",
1185
+ "required_control": "CMMC L2+ publisher-side practice binding SLSA L3 + signed SBOM + VEX + CSAF for DIB-shipped artifacts."
1186
+ }
1187
+ ],
1188
+ "escalation_criteria": [
1189
+ {
1190
+ "condition": "(no-rekor-entry-for-latest-release == true OR no-rekor-entry-for-latest-release == inconclusive) AND ssdf-claimed-cra-not-ready == true",
1191
+ "action": "page_on_call"
1192
+ },
1193
+ {
1194
+ "condition": "sbom-absent-or-unsigned == true AND product_is_eu_cra_class_ii_claimed == true",
1195
+ "action": "page_on_call"
1196
+ },
1197
+ {
1198
+ "condition": "no-security-md == true AND no-security-txt == true AND product_is_public == true",
1199
+ "action": "page_on_call"
1200
+ },
1201
+ {
1202
+ "condition": "publish-workflow-uses-static-token == true AND blast_radius_score >= 4",
1203
+ "action": "page_on_call"
1204
+ },
1205
+ {
1206
+ "condition": "tag-protection-absent == true AND publish_triggers_on_tags == true",
1207
+ "action": "raise_severity"
1208
+ },
1209
+ {
1210
+ "condition": "skill-signing-but-verification-not-gated == true",
1211
+ "action": "raise_severity"
1212
+ },
1213
+ {
1214
+ "condition": "vex-feed-absent == true AND filed_cves_against_product > 0",
1215
+ "action": "trigger_playbook",
1216
+ "target_playbook": "sbom"
1217
+ },
1218
+ {
1219
+ "condition": "blast_radius_score >= 4",
1220
+ "action": "trigger_playbook",
1221
+ "target_playbook": "framework"
1222
+ },
1223
+ {
1224
+ "condition": "compliance_theater_check.verdict == 'theater' AND jurisdiction_obligations contains 'EU'",
1225
+ "action": "notify_legal"
1226
+ },
1227
+ {
1228
+ "condition": "release-signed-with-personal-gpg-key == true AND blast_radius_score >= 4",
1229
+ "action": "page_on_call"
1230
+ }
1231
+ ]
1232
+ },
1233
+ "validate": {
1234
+ "remediation_paths": [
1235
+ {
1236
+ "id": "adopt-registry-trusted-publisher-oidc",
1237
+ "description": "Replace long-lived publisher tokens (NPM_TOKEN / PYPI_TOKEN / CARGO_TOKEN / RUBYGEMS_API_KEY) with registry Trusted Publisher OIDC. For npm: configure Trusted Publisher in package settings, set permissions.id-token: write + --provenance in workflow. For PyPI: configure Trusted Publisher, use pypa/gh-action-pypi-publish with no API token. For crates: enable trustpub. For RubyGems: enable Trusted Publisher (gem 2025-02+).",
1238
+ "preconditions": [
1239
+ "registry_supports_trusted_publisher == true",
1240
+ "workflow_modifiable == true"
1241
+ ],
1242
+ "priority": 1,
1243
+ "compensating_controls": [
1244
+ "delete_static_publisher_secret_post_migration",
1245
+ "audit_recent_publishes_for_token_leak_indicators"
1246
+ ],
1247
+ "estimated_time_hours": 4
1248
+ },
1249
+ {
1250
+ "id": "wire-cosign-signing-and-rekor-verification-into-release-workflow",
1251
+ "description": "Add cosign sign-blob (or sigstore-python / cosign-installer) signing step to the release workflow producing a Sigstore Rekor entry per release artifact. Add a cosign verify-blob step IN THE SAME WORKFLOW RUN gating the publish step. Verify the certificate identity matches the expected workflow OIDC identity (--certificate-identity-regexp).",
1252
+ "preconditions": [
1253
+ "workflow_modifiable == true",
1254
+ "release_pipeline_runs_on_github_hosted_runner == true"
1255
+ ],
1256
+ "priority": 2,
1257
+ "compensating_controls": [
1258
+ "rekor_entry_search_documented_in_security_md",
1259
+ "cosign_pub_committed_to_repo_for_offline_verification"
1260
+ ],
1261
+ "estimated_time_hours": 6
1262
+ },
1263
+ {
1264
+ "id": "enforce-tag-protection-and-pinned-action-shas",
1265
+ "description": "Enable tag protection rules on v* pattern via GitHub repo settings; require signed tags. Replace all third-party action references in release / publish workflows with 40-char SHA pins; add Dependabot config for action-sha update PRs. Restrict publish workflow trigger to protected events.",
1266
+ "preconditions": [
1267
+ "repo_admin_access == true"
1268
+ ],
1269
+ "priority": 3,
1270
+ "compensating_controls": [
1271
+ "branch_protection_on_main_with_required_reviewers",
1272
+ "codeowners_for_release_workflow_files"
1273
+ ],
1274
+ "estimated_time_hours": 3
1275
+ },
1276
+ {
1277
+ "id": "publish-signed-sbom-with-every-release",
1278
+ "description": "Add SBOM generation step (CycloneDX 1.6 via cyclonedx-cli or syft) producing a transitive-complete SBOM as a build artifact. Sign with cosign. Attach to GitHub release assets AND publish to a stable URL. Verify component count vs lockfile resolution to ensure transitive completeness.",
1279
+ "preconditions": [
1280
+ "workflow_modifiable == true",
1281
+ "sbom_tooling_supports_target_ecosystem == true"
1282
+ ],
1283
+ "priority": 4,
1284
+ "compensating_controls": [
1285
+ "sbom_completeness_gate_in_ci",
1286
+ "sbom_signature_verification_documented_in_security_md"
1287
+ ],
1288
+ "estimated_time_hours": 6
1289
+ },
1290
+ {
1291
+ "id": "publish-vex-feed-and-csaf-pipeline",
1292
+ "description": "Stand up CSAF 2.0 VEX feed: a stable URL at https://${product_domain}/.well-known/csaf/ serving signed CSAF 2.1 documents. For each CVE filed against the product (including historical), produce a VEX statement (not_affected / affected / fixed / under_investigation) within 14 days. Pre-deploy CSAF advisory template for EU CRA Art.14 24h notification compliance.",
1293
+ "preconditions": [
1294
+ "security_team_capacity_for_csaf == true",
1295
+ "product_has_primary_domain == true"
1296
+ ],
1297
+ "priority": 5,
1298
+ "compensating_controls": [
1299
+ "github_security_advisory_used_as_interim_vex_carrier",
1300
+ "vex_template_in_security_md"
1301
+ ],
1302
+ "estimated_time_hours": 16
1303
+ },
1304
+ {
1305
+ "id": "establish-coordinated-disclosure-path",
1306
+ "description": "Add SECURITY.md to repo root documenting disclosure intake (private vulnerability reporting URL, security@${domain} email, PGP key fingerprint, response SLA per ISO 30111). Add /.well-known/security.txt per RFC 9116 with Contact + Expires + Encryption + Policy + Acknowledgments fields. Enable GitHub private vulnerability reporting on the repo.",
1307
+ "preconditions": [
1308
+ "repo_admin_access == true",
1309
+ "primary_domain_dns_modifiable == true OR static_hosting_modifiable == true"
1310
+ ],
1311
+ "priority": 6,
1312
+ "compensating_controls": [
1313
+ "security_md_linked_from_readme",
1314
+ "security_txt_expires_date_calendared_for_renewal"
1315
+ ],
1316
+ "estimated_time_hours": 4
1317
+ },
1318
+ {
1319
+ "id": "enforce-frozen-lockfile-and-integrity-pins",
1320
+ "description": "Change all release-workflow install commands to frozen-lockfile variants (`npm ci`, `pnpm install --frozen-lockfile`, `pip install --require-hashes -r requirements.txt`, `cargo build --locked`, `bundle install --frozen`). Regenerate any lockfile entries lacking integrity hashes (npm: --package-lock-only; pip: pip-compile --generate-hashes). Add CI gate rejecting any lockfile without integrity.",
1321
+ "preconditions": [
1322
+ "workflow_modifiable == true",
1323
+ "lockfile_regeneration_does_not_break_build == true"
1324
+ ],
1325
+ "priority": 7,
1326
+ "compensating_controls": [
1327
+ "lockfile_review_in_pr_template",
1328
+ "registry_url_pinned_in_install_config"
1329
+ ],
1330
+ "estimated_time_hours": 6
1331
+ },
1332
+ {
1333
+ "id": "wire-skill-or-plugin-signature-verification-into-install-path",
1334
+ "description": "For AI-tool / plugin / skill publishers: add Ed25519 / cosign signature verification step that gates the install step in the SAME workflow run AND in the consumer-side install path. Sign every shipped skill / plugin manifest. Publish public key + Rekor identity in SECURITY.md.",
1335
+ "preconditions": [
1336
+ "publisher_ships_ai_tool_artifacts == true",
1337
+ "consumer_install_path_modifiable == true"
1338
+ ],
1339
+ "priority": 8,
1340
+ "compensating_controls": [
1341
+ "install_time_signature_verification_documented_in_readme",
1342
+ "public_key_committed_to_repo_for_offline_verification"
1343
+ ],
1344
+ "estimated_time_hours": 12
1345
+ },
1346
+ {
1347
+ "id": "document-five-year-support-commitment",
1348
+ "description": "Add an EU CRA Art.10-aligned support-lifecycle statement to SECURITY.md and product trust portal: per-product end-of-support date (minimum 5y from initial sale / first availability), security-update commitment, end-of-support notification template. Calendar the renewal review.",
1349
+ "preconditions": [
1350
+ "product_ships_to_eu_market == true"
1351
+ ],
1352
+ "priority": 9,
1353
+ "compensating_controls": [
1354
+ "support_lifecycle_in_release_notes_per_release"
1355
+ ],
1356
+ "estimated_time_hours": 4
1357
+ },
1358
+ {
1359
+ "id": "policy-exception",
1360
+ "description": "Where a publisher-posture gap cannot be remediated within the compliance window — typical case: API stability promise prevents removing a deprecated transitive dep before next major version; OR registry doesn't yet support Trusted Publisher; OR a Class II conformity assessment is in progress — generate an auditor-ready policy exception via policy-exception-gen with compensating controls and time-bound sunset date.",
1361
+ "preconditions": [
1362
+ "remediation_paths[1..9] blocked for at least one finding",
1363
+ "ciso_or_product_owner_acceptance_obtainable == true"
1364
+ ],
1365
+ "priority": 10,
1366
+ "compensating_controls": [
1367
+ "security_advisory_published_for_known_residual",
1368
+ "parallel_path_or_replacement_dependency_in_roadmap",
1369
+ "documented_sunset_date_for_residual",
1370
+ "enhanced_logging_for_exploitation_indicators_in_residual_area"
1371
+ ],
1372
+ "estimated_time_hours": 8
1373
+ }
1374
+ ],
1375
+ "validation_tests": [
1376
+ {
1377
+ "id": "publish-workflow-uses-oidc",
1378
+ "test": "Re-read .github/workflows/*.yml release/publish job. Confirm (a) permissions.id-token: write at job level, (b) no secrets.NPM_TOKEN / PYPI_TOKEN / CARGO_TOKEN reference, (c) Trusted Publisher status verified via registry API (npm: package-level config; PyPI: project-level config; crates: trustpub status).",
1379
+ "expected_result": "OIDC publish in place; no long-lived publisher token referenced.",
1380
+ "test_type": "functional"
1381
+ },
1382
+ {
1383
+ "id": "rekor-entry-exists-for-latest-release",
1384
+ "test": "Compute sha256 of latest release artifact. Run `rekor-cli search --sha <hash>` AND `cosign verify-blob --certificate-identity-regexp '^https://github.com/${owner}/${repo}/' --certificate-oidc-issuer https://token.actions.githubusercontent.com <artifact>`.",
1385
+ "expected_result": "Rekor entry returns a UUID matching the publish workflow's OIDC identity; cosign verify succeeds.",
1386
+ "test_type": "functional"
1387
+ },
1388
+ {
1389
+ "id": "tag-protection-rejects-unprotected-tag-push",
1390
+ "test": "Attempt to push a test tag (e.g. v0.0.0-test-rejection) from a non-protected branch via a non-admin actor. Confirm GitHub rejects the push per tag protection.",
1391
+ "expected_result": "Push rejected with tag-protection-rule error.",
1392
+ "test_type": "negative"
1393
+ },
1394
+ {
1395
+ "id": "sbom-signature-verifies",
1396
+ "test": "Download SBOM artifact from the latest release. Run `cosign verify-blob --signature <sbom>.sig <sbom>` against the documented signing identity.",
1397
+ "expected_result": "Signature verifies; SBOM matches the release version.",
1398
+ "test_type": "functional"
1399
+ },
1400
+ {
1401
+ "id": "sbom-transitive-completeness",
1402
+ "test": "Compare SBOM component count against the lockfile transitive resolution (npm ls --depth=Infinity, pip freeze + transitive resolve, cargo tree --depth=Infinity). Allow ±5% tolerance for tooling differences.",
1403
+ "expected_result": "SBOM count >= 95% of transitive count.",
1404
+ "test_type": "functional"
1405
+ },
1406
+ {
1407
+ "id": "vex-statement-coverage-for-filed-cves",
1408
+ "test": "List all CVEs filed against the product (via NVD search by CPE, GHSA, OSV.dev). Confirm each has a published VEX statement (CSAF 2.1 VEX or OpenVEX) within 14 days of CVE publication.",
1409
+ "expected_result": "100% VEX coverage for filed CVEs, with timeline within 14d.",
1410
+ "test_type": "functional"
1411
+ },
1412
+ {
1413
+ "id": "security-txt-and-security-md-present",
1414
+ "test": "HTTP GET https://${product_domain}/.well-known/security.txt — confirm 200 OK with valid RFC 9116 fields. Read repo SECURITY.md — confirm disclosure intake + SLA + PGP key. Confirm GitHub private vulnerability reporting enabled.",
1415
+ "expected_result": "All three present and current; security.txt Expires field > now + 30d.",
1416
+ "test_type": "functional"
1417
+ },
1418
+ {
1419
+ "id": "skill-or-plugin-verification-gates-install",
1420
+ "test": "For AI-tool publishers: attempt to install / load a deliberately-unsigned skill or plugin into the consumer-side install path. Confirm the install / load is rejected with a signature-failure error BEFORE any code from the artifact executes.",
1421
+ "expected_result": "Install rejected pre-execution; no code from the unsigned artifact runs.",
1422
+ "test_type": "negative"
1423
+ },
1424
+ {
1425
+ "id": "release-build-reproducibility",
1426
+ "test": "Run the release build twice from the same tag on two different ephemeral runners (or same runner with clean cache). Compare sha256 of output artifacts.",
1427
+ "expected_result": "Bit-for-bit identical OR documented non-reproducible-fields list bounded to known sources (timestamps, build IDs) that don't carry executable code.",
1428
+ "test_type": "regression"
1429
+ },
1430
+ {
1431
+ "id": "frozen-lockfile-rejects-mid-build-resolution",
1432
+ "test": "Add a deliberately-stale lockfile entry (newer manifest version than lockfile reflects) to a test branch. Run the release workflow.",
1433
+ "expected_result": "Install step fails with lockfile-mismatch / frozen-lockfile error; release does not proceed.",
1434
+ "test_type": "negative"
1435
+ },
1436
+ {
1437
+ "id": "lockfile-substitution-attack-blocked",
1438
+ "test": "Exploit-replay: stage a malicious lockfile entry attempting to substitute a known package with a typosquat (e.g. `react@x.y.z` integrity hash replaced with attacker-crafted package's integrity). Run the release workflow.",
1439
+ "expected_result": "Install step fails on integrity-hash mismatch (legitimate package's expected hash doesn't match attacker's published artifact). Release does not proceed.",
1440
+ "test_type": "exploit_replay"
1441
+ },
1442
+ {
1443
+ "id": "csaf-advisory-template-renders-under-24h",
1444
+ "test": "Run a dry-run of the CSAF advisory pipeline with a synthetic actively-exploited CVE. Confirm draft is rendered, reviewed, signed, and ready for ENISA single-reporting-platform submission in < 24h.",
1445
+ "expected_result": "End-to-end dry-run completes in < 24h with signed CSAF 2.1 advisory.",
1446
+ "test_type": "functional"
1447
+ }
1448
+ ],
1449
+ "residual_risk_statement": {
1450
+ "risk": "Publisher posture closes operational supply-chain controls but cannot eliminate (a) maintainer-position long-game compromise (XZ-Utils class — credible insider with multi-year patience bypasses signing because they ARE the signing identity), (b) registry-side compromise (registry takeover affects all OIDC-published packages), (c) downstream consumer mis-verification (consumers who skip signature verification accept any signed-or-not artifact), (d) zero-day in the release toolchain itself (cosign / sigstore / Rekor implementation bugs).",
1451
+ "why_remains": "Signature attestation proves authorship not safety. OIDC publish moves the trust anchor to GitHub / registry — those become the load-bearing surfaces. Reproducible builds detect divergence but require third-party rebuild capacity. Consumers must verify; publishers cannot enforce verification on the consumer side. Transparency-log entries are tamper-evident but not tamper-proof. Five-year support obligations under EU CRA Art.10 introduce sustained cost the publisher must budget for.",
1452
+ "acceptance_level": "ciso",
1453
+ "compensating_controls_in_place": [
1454
+ "oidc_publish_with_rekor_entry_per_release",
1455
+ "tag_protection_with_signed_tags",
1456
+ "signed_sbom_distributed_with_every_release",
1457
+ "vex_feed_with_csaf_advisory_pipeline",
1458
+ "rfc_9116_security_txt_with_private_vuln_reporting",
1459
+ "skill_or_plugin_signature_verification_gated_in_install_path",
1460
+ "reproducible_build_with_periodic_third_party_rebuild_check",
1461
+ "maintainer_account_2fa_with_hardware_token",
1462
+ "release_workflow_codeowners_with_two-person_review"
1463
+ ]
1464
+ },
1465
+ "evidence_requirements": [
1466
+ {
1467
+ "evidence_type": "scan_report",
1468
+ "description": "Full publisher-posture scan output: theater fingerprint test results, RWEP per finding, framework gap mapping.",
1469
+ "retention_period": "7_years",
1470
+ "framework_satisfied": [
1471
+ "nist-800-53-SR-3",
1472
+ "nist-800-53-SR-4",
1473
+ "nist-800-218-PS-3",
1474
+ "iso-27001-2022-A.8.30",
1475
+ "nis2-art21-2d",
1476
+ "eu-cra-art13"
1477
+ ]
1478
+ },
1479
+ {
1480
+ "evidence_type": "attestation",
1481
+ "description": "Sigstore / in-toto / SLSA build provenance attestation per release artifact, retrievable via Rekor entry UUID.",
1482
+ "retention_period": "7_years",
1483
+ "framework_satisfied": [
1484
+ "nist-800-53-SR-4",
1485
+ "nist-800-218-PS-3",
1486
+ "slsa-l3",
1487
+ "eu-cra-art13"
1488
+ ]
1489
+ },
1490
+ {
1491
+ "evidence_type": "config_diff",
1492
+ "description": "Before/after diffs: workflow YAML (token → OIDC), lockfile (no-integrity → integrity), tag protection (absent → enforced), SECURITY.md (absent → present), security.txt (absent → present).",
1493
+ "retention_period": "7_years",
1494
+ "framework_satisfied": [
1495
+ "nist-800-53-CM-3",
1496
+ "iso-27001-2022-A.8.32",
1497
+ "soc2-cc8.1"
1498
+ ]
1499
+ },
1500
+ {
1501
+ "evidence_type": "exploit_replay_negative",
1502
+ "description": "Lockfile-substitution attack negative test + unsigned-skill install rejection + tag-protection rejection logs.",
1503
+ "retention_period": "1_year",
1504
+ "framework_satisfied": [
1505
+ "soc2-cc7.1",
1506
+ "iso-27001-2022-A.8.8",
1507
+ "nist-800-218-PW-4"
1508
+ ]
1509
+ },
1510
+ {
1511
+ "evidence_type": "patch_record",
1512
+ "description": "Release workflow CI run records for each release with OIDC identity, Rekor UUID, SBOM signature, VEX feed entry timestamp.",
1513
+ "retention_period": "7_years",
1514
+ "framework_satisfied": [
1515
+ "nist-800-53-SI-2",
1516
+ "iso-27001-2022-A.8.8",
1517
+ "nis2-art21-2c",
1518
+ "eu-cra-art14"
1519
+ ]
1520
+ },
1521
+ {
1522
+ "evidence_type": "attestation",
1523
+ "description": "Signed exceptd attestation file with evidence_hash, theater-fingerprint pass/fail per fingerprint, RWEP at detection vs post-remediation, EU CRA Art.10/13/14 readiness flags.",
1524
+ "retention_period": "7_years",
1525
+ "framework_satisfied": [
1526
+ "nist-800-53-CA-7",
1527
+ "iso-27001-2022-A.5.36",
1528
+ "nis2-art21-2d",
1529
+ "dora-art28",
1530
+ "eu-cra-art13"
1531
+ ]
1532
+ }
1533
+ ],
1534
+ "regression_trigger": [
1535
+ {
1536
+ "condition": "new_release",
1537
+ "interval": "on_event"
1538
+ },
1539
+ {
1540
+ "condition": "release_workflow_modified",
1541
+ "interval": "on_event"
1542
+ },
1543
+ {
1544
+ "condition": "new_cve_filed_against_product",
1545
+ "interval": "on_event"
1546
+ },
1547
+ {
1548
+ "condition": "publisher_credential_rotated_or_added",
1549
+ "interval": "on_event"
1550
+ },
1551
+ {
1552
+ "condition": "registry_publisher_settings_changed",
1553
+ "interval": "on_event"
1554
+ },
1555
+ {
1556
+ "condition": "monthly",
1557
+ "interval": "30d"
1558
+ },
1559
+ {
1560
+ "condition": "pre_major_release",
1561
+ "interval": "on_event"
1562
+ }
1563
+ ]
1564
+ },
1565
+ "close": {
1566
+ "evidence_package": {
1567
+ "bundle_format": "csaf-2.0",
1568
+ "contents": [
1569
+ "scan_report",
1570
+ "attestation",
1571
+ "config_diff",
1572
+ "exploit_replay_negative",
1573
+ "patch_record",
1574
+ "framework_gap_mapping",
1575
+ "compliance_theater_verdict",
1576
+ "residual_risk_statement"
1577
+ ],
1578
+ "destination": "grc_platform_api",
1579
+ "signed": true
1580
+ },
1581
+ "learning_loop": {
1582
+ "enabled": true,
1583
+ "lesson_template": {
1584
+ "attack_vector": "Publisher-side supply-chain compromise via (a) long-lived publisher token leak → registry takeover, (b) tag-protection absent → any-branch v* push triggers publish, (c) personal-laptop GPG signing key compromise → XZ-class infiltration, (d) SLSA L3 claim without Rekor entry → unverifiable provenance, (e) skill/plugin signature verification not gated in install path → CVE-2026-30615 class zero-interaction RCE on developer endpoints, (f) VEX feed absent → downstream consumers cannot triage filed CVEs against their use, (g) no disclosure path → researchers disclose publicly or not at all.",
1585
+ "control_gap": "Publisher-side controls in NIST 800-53 SR-3/4/5, NIST 800-218 SSDF, ISO 27001:2022 A.8.30/A.5.20, SOC 2 CC8.1/CC9.2, NIS2 Art.21(2)(d), DORA Art.28, UK CAF C1.b, AU Essential 8 E1, CMMC SI.L2-3.4.4 did not generate signal because they treat the publisher as an acquirer / supplier / change-managed internal rather than as the producer of artifacts thousands of consumers depend on. SBOM-generation, vulnerability-tracking, and procurement-event lenses do not bind OIDC publish, Sigstore Rekor entry, signed SBOM distribution, transitive completeness, VEX issuance, RFC 9116 disclosure path, tag protection, frozen-lockfile install, skill verification gate, or EU CRA Art.10 five-year support commitment.",
1586
+ "framework_gap": "NIST 800-53 SR-3/4/5, NIST 800-218 SSDF PS.3.2/PW.4/RV.2, ISO 27001:2022 A.8.30/A.5.20, SOC 2 CC8.1/CC9.2, PCI DSS 4.0 6.3, NIS2 Art.21(2)(d), DORA Art.28, UK CAF C1.b/B4.d, AU Essential 8 E1, CMMC SI.L2-3.4.4 all permit publisher posture that omits OIDC publish, Rekor attestation, signed SBOM distribution, VEX feed, and disclosure path. Framework lag = ~540 days behind operational tooling (Sigstore, SLSA v1.0, CycloneDX 1.6, CSAF 2.1, npm/PyPI/crates Trusted Publisher); ~18 months ahead of EU CRA Art.10/13/14 binding (2027).",
1587
+ "new_control_requirement": "Add publisher-side control class binding: (a) OIDC publish via registry Trusted Publisher with id-token write permission, (b) Sigstore Rekor transparency-log entry per release artifact, (c) cosign verification step gating the publish step in the SAME workflow run, (d) signed CycloneDX 1.6 or SPDX 3.0 SBOM with transitive completeness distributed in release assets, (e) CSAF 2.1 VEX feed with statement issued within 14d of every filed CVE, (f) RFC 9116 security.txt at primary product domain plus SECURITY.md plus GitHub private vulnerability reporting plus pre-deployed CSAF advisory template for EU CRA Art.14 24h notification, (g) tag protection on v* pattern with signed tags, (h) frozen-lockfile install in release pipeline with integrity-hashed lockfile gate in CI, (i) third-party action references SHA-pinned with Dependabot config, (j) for AI-tool / plugin / skill publishers: Ed25519 or cosign signature verification gated in consumer-side install path with public key + Rekor identity published in SECURITY.md, (k) documented five-year support commitment per product per EU CRA Art.10, (l) reproducible build with periodic third-party rebuild check."
1588
+ },
1589
+ "feeds_back_to_skills": [
1590
+ "supply-chain-integrity",
1591
+ "coordinated-vuln-disclosure",
1592
+ "framework-gap-analysis",
1593
+ "compliance-theater",
1594
+ "zeroday-gap-learn"
1595
+ ]
1596
+ },
1597
+ "notification_actions": [
1598
+ {
1599
+ "obligation_ref": "EU/EU CRA Art.14 24h",
1600
+ "deadline": "computed_at_runtime",
1601
+ "recipient": "regulator_email",
1602
+ "evidence_attached": [
1603
+ "affected_product_identification",
1604
+ "exploitation_evidence",
1605
+ "mitigation_status",
1606
+ "csaf_advisory_draft"
1607
+ ],
1608
+ "draft_notification": "EU CRA Art.14 24-hour notification: Product ${product_id} (manufacturer: ${entity_name}) contains an actively-exploited vulnerability ${matched_cve_id}. Affected versions: ${affected_versions}. Exploitation evidence: ${exploitation_evidence}. Mitigation status: ${mitigation_status}. Security update URL: ${update_url}. CSAF advisory: ${csaf_advisory_url}. Full assessment to follow within 72 hours."
1609
+ },
1610
+ {
1611
+ "obligation_ref": "EU/EU CRA Art.14 72h",
1612
+ "deadline": "computed_at_runtime",
1613
+ "recipient": "regulator_email",
1614
+ "evidence_attached": [
1615
+ "full_vulnerability_assessment",
1616
+ "corrective_measures",
1617
+ "published_csaf_advisory"
1618
+ ],
1619
+ "draft_notification": "EU CRA Art.14 72-hour full assessment: Product ${product_id}, CVE ${matched_cve_id}. Full vulnerability assessment: ${assessment_summary}. Corrective measures deployed: ${corrective_measures}. Published CSAF advisory: ${csaf_advisory_url}. Downstream consumer notification: ${consumer_notification_status}."
1620
+ },
1621
+ {
1622
+ "obligation_ref": "EU/EU CRA Art.13 / Annex I 8760h",
1623
+ "deadline": "computed_at_runtime",
1624
+ "recipient": "internal_legal",
1625
+ "evidence_attached": [
1626
+ "sbom_per_product",
1627
+ "conformity_assessment",
1628
+ "vulnerability_handling_procedure",
1629
+ "security_update_record",
1630
+ "coordinated_disclosure_policy"
1631
+ ],
1632
+ "draft_notification": "EU CRA Art.13 / Annex I annual conformity assessment: ${entity_name} attests product cybersecurity requirements for ${product_id}. Signed SBOM: ${sbom_url}. Conformity assessment outcome: ${conformity_status}. Vulnerability handling procedure: ${vh_procedure_url}. Security update record: ${update_record}. Coordinated disclosure policy: ${disclosure_policy_url}."
1633
+ },
1634
+ {
1635
+ "obligation_ref": "EU/EU CRA Art.10 43800h",
1636
+ "deadline": "computed_at_runtime",
1637
+ "recipient": "internal_legal",
1638
+ "evidence_attached": [
1639
+ "five_year_security_update_commitment",
1640
+ "support_lifecycle_record",
1641
+ "end_of_support_notice_template"
1642
+ ],
1643
+ "draft_notification": "EU CRA Art.10 five-year security update obligation: ${entity_name} attests support-lifecycle commitment for ${product_id}. Initial sale / first availability: ${first_availability_date}. End of support: ${eos_date} (minimum first_availability + 5y). Security update commitment: ${commitment_text}. End-of-support notice template: ${notice_template_url}."
1644
+ },
1645
+ {
1646
+ "obligation_ref": "EU/NIS2 Art.21(2)(d) 720h",
1647
+ "deadline": "computed_at_runtime",
1648
+ "recipient": "internal_legal",
1649
+ "evidence_attached": [
1650
+ "supplier_security_policy",
1651
+ "third_party_risk_register",
1652
+ "publisher_attestation_inventory"
1653
+ ],
1654
+ "draft_notification": "NIS2 Art.21(2)(d) supply chain security policy evidence: ${entity_name} attests publisher-side supply chain security. Supplier security policy: ${policy_url}. Third-party risk register: ${register_summary}. Publisher attestation inventory: Sigstore Rekor entries ${rekor_count}, signed SBOMs ${sbom_count}, VEX statements ${vex_count}, OIDC-published releases ${oidc_count}."
1655
+ },
1656
+ {
1657
+ "obligation_ref": "EU/DORA Art.28 720h",
1658
+ "deadline": "computed_at_runtime",
1659
+ "recipient": "internal_legal",
1660
+ "evidence_attached": [
1661
+ "ict_third_party_register",
1662
+ "concentration_risk_assessment",
1663
+ "subcontracting_inventory"
1664
+ ],
1665
+ "draft_notification": "DORA Art.28 third-party ICT risk submission: ${entity_name} attests publisher-side dependency risk management. Register: ${register_summary}. Concentration risk: ${concentration_summary}. Subcontracting (transitive dep) inventory: ${transitive_inventory_summary}."
1666
+ },
1667
+ {
1668
+ "obligation_ref": "US/OMB M-22-09 / EO 14028 8760h",
1669
+ "deadline": "computed_at_runtime",
1670
+ "recipient": "internal_legal",
1671
+ "evidence_attached": [
1672
+ "cisa_secure_software_attestation_form",
1673
+ "sbom_per_product",
1674
+ "ssdf_alignment_evidence"
1675
+ ],
1676
+ "draft_notification": "OMB M-22-09 / EO 14028 annual secure software attestation: ${entity_name} attests SSDF alignment for ${product_id}. CISA Secure Software Attestation Form: ${form_url}. Signed SBOM per product: ${sbom_url}. SSDF alignment evidence: ${ssdf_evidence_summary}."
1677
+ },
1678
+ {
1679
+ "obligation_ref": "US/CISA Secure-by-Design Pledge 4320h",
1680
+ "deadline": "computed_at_runtime",
1681
+ "recipient": "internal_legal",
1682
+ "evidence_attached": [
1683
+ "secure_by_design_attestation_text",
1684
+ "measurable_progress_evidence_per_goal"
1685
+ ],
1686
+ "draft_notification": "CISA Secure-by-Design Pledge self-attestation: ${entity_name} attests measurable progress on the seven Secure-by-Design goals. Attestation text: ${attestation_text}. Measurable progress evidence: ${progress_evidence_per_goal}."
1687
+ },
1688
+ {
1689
+ "obligation_ref": "UK/UK CAF (NCSC) C1.b / B4.d 720h",
1690
+ "deadline": "computed_at_runtime",
1691
+ "recipient": "internal_legal",
1692
+ "evidence_attached": [
1693
+ "supplier_assurance_register",
1694
+ "release_pipeline_security_attestation"
1695
+ ],
1696
+ "draft_notification": "UK CAF C1.b / B4.d supplier assurance + release pipeline attestation: ${entity_name}. Supplier assurance register: ${register_summary}. Release pipeline security attestation: ${attestation_summary} (OIDC publish, Rekor entries, signed SBOM, VEX feed)."
1697
+ },
1698
+ {
1699
+ "obligation_ref": "AU/AU ISM (ACSC) Guidelines for Software Development 720h",
1700
+ "deadline": "computed_at_runtime",
1701
+ "recipient": "internal_legal",
1702
+ "evidence_attached": [
1703
+ "secure_development_lifecycle_record",
1704
+ "signed_release_artifacts"
1705
+ ],
1706
+ "draft_notification": "AU ISM Guidelines for Software Development evidence: ${entity_name}. Secure development lifecycle record: ${sdl_summary}. Signed release artifacts: ${signed_release_summary}."
1707
+ }
1708
+ ],
1709
+ "exception_generation": {
1710
+ "trigger_condition": "remediation_blocked == true OR (api_stability_promise_prevents_dependency_removal == true) OR (registry_does_not_support_trusted_publisher == true) OR (eu_cra_class_ii_conformity_assessment_in_progress == true)",
1711
+ "exception_template": {
1712
+ "scope": "Publisher-posture gap(s) ${finding_ids} on product ${product_id} cannot be remediated within the compliance window. Blocking factors: ${blocking_factors} (API stability promise prevents removing deprecated transitive dep before next major version; registry doesn't yet support Trusted Publisher; EU CRA Class II conformity assessment in progress; vendor-side fix pending for cosign/sigstore/Rekor implementation bug; five-year support commitment requires budgeting beyond current cycle).",
1713
+ "duration": "until_vendor_patch",
1714
+ "compensating_controls": [
1715
+ "security_advisory_published_for_known_residual",
1716
+ "parallel_replacement_dependency_path_in_roadmap",
1717
+ "documented_sunset_date_for_residual",
1718
+ "enhanced_logging_for_exploitation_indicators_in_residual_area",
1719
+ "github_security_advisory_used_as_interim_vex_carrier",
1720
+ "short_lived_publisher_token_with_30d_rotation_when_oidc_unavailable",
1721
+ "two-person_review_on_release_workflow_changes",
1722
+ "third_party_rebuild_check_documented_quarterly"
1723
+ ],
1724
+ "risk_acceptance_owner": "ciso",
1725
+ "auditor_ready_language": "Pursuant to ${framework_id} ${control_id} (Supply Chain Protection / Provenance / Secure Software Development / Outsourced Development / Supply Chain Security / Manufacturer Obligations under EU CRA Art.10/13/14), the manufacturer documents a time-bound risk acceptance for publisher-posture gap(s) ${finding_ids} on product ${product_id}. Specific gap(s): ${specific_gaps}. Blocking factor(s): ${blocking_factors}. Compensating controls in place during exception window: ${compensating_controls}. VEX statement for any associated CVE: ${vex_statement} (under_investigation / not_affected / affected / fixed). Affected downstream consumer notification path: ${consumer_notification_path}. Detection coverage during exception: continuous publisher-posture monitoring via exceptd library-author playbook, enhanced logging for exploitation indicators in the residual area, KEV-feed integration alerting on new KEV listing for any vendored dep. The manufacturer accepts that current framework controls (NIST 800-53 SR-3/4/5 / NIST 800-218 SSDF / ISO 27001:2022 A.8.30/A.5.20 / SOC 2 CC8.1/CC9.2 / NIS2 Art.21(2)(d) / DORA Art.28 / EU CRA Art.10/13/14 / UK CAF C1.b/B4.d / AU Essential 8 E1 / CMMC SI.L2-3.4.4) permit the structural gap documented in ${exceptd_framework_gap_mapping_ref}, and that the manufacturer's compensating controls during the exception window are operationally sufficient pending closure. Risk accepted by ${ciso_or_product_owner_name} on ${acceptance_date}. Time-bound until ${duration_expiry} (next major version release that permits API-breaking removal; registry Trusted Publisher rollout; conformity assessment completion; OR ${default_90d_expiry}, whichever is first). Sunset path documented in roadmap ticket ${roadmap_ticket_url}. Re-evaluation triggers: blocker resolved, new CVE filed against the residual area, new KEV listing for any vendored dep, active-exploitation indicator fires, OR scheduled expiry. This exception is recorded in the manufacturer's GRC platform and surfaces in EU CRA Art.13 annual conformity assessment + NIS2 Art.21(2)(d) supply chain security policy submission + OMB M-22-09 annual attestation as a documented exception with sunset date."
1726
+ }
1727
+ },
1728
+ "regression_schedule": {
1729
+ "next_run": "computed_at_runtime",
1730
+ "trigger": "both",
1731
+ "notify_on_skip": true
1732
+ }
1733
+ }
1734
+ },
1735
+ "directives": [
1736
+ {
1737
+ "id": "published-artifact-audit",
1738
+ "title": "Full publisher-posture audit: release pipeline, signing, SBOM, lockfiles, vendored deps, branch+tag protection, OIDC vs static credentials, disclosure path",
1739
+ "applies_to": {
1740
+ "always": true
1741
+ }
1742
+ },
1743
+ {
1744
+ "id": "vex-issuance-gap",
1745
+ "title": "VEX issuance posture: do you publish CSAF 2.1 VEX statements for every CVE filed against your product within 14 days?",
1746
+ "applies_to": {
1747
+ "always": true
1748
+ },
1749
+ "phase_overrides": {
1750
+ "direct": {
1751
+ "rwep_threshold": {
1752
+ "escalate": 70,
1753
+ "monitor": 40,
1754
+ "close": 25
1755
+ }
1756
+ }
1757
+ }
1758
+ },
1759
+ {
1760
+ "id": "slsa-level-claim-audit",
1761
+ "title": "SLSA L3 / L4 attestation claim vs reality: Rekor entries, in-toto attestation chain, reproducible build, third-party verification",
1762
+ "applies_to": {
1763
+ "always": true
1764
+ },
1765
+ "phase_overrides": {
1766
+ "direct": {
1767
+ "rwep_threshold": {
1768
+ "escalate": 75,
1769
+ "monitor": 45,
1770
+ "close": 28
1771
+ }
1772
+ }
1773
+ }
1774
+ },
1775
+ {
1776
+ "id": "skill-or-plugin-signing-verification-gate",
1777
+ "title": "For AI-tool / plugin / skill publishers: signature verification gated in consumer-side install path (CVE-2026-30615 class prevention)",
1778
+ "applies_to": {
1779
+ "always": true
1780
+ },
1781
+ "phase_overrides": {
1782
+ "direct": {
1783
+ "rwep_threshold": {
1784
+ "escalate": 70,
1785
+ "monitor": 40,
1786
+ "close": 25
1787
+ }
1788
+ }
1789
+ }
1790
+ }
1791
+ ]
1792
+ }