@blamejs/exceptd-skills 0.16.25 → 0.16.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/AGENTS.md +5 -5
  2. package/ARCHITECTURE.md +3 -3
  3. package/CHANGELOG.md +28 -0
  4. package/CONTEXT.md +2 -2
  5. package/README.md +6 -6
  6. package/agents/threat-researcher.md +2 -2
  7. package/bin/exceptd.js +41 -8
  8. package/data/_indexes/_meta.json +41 -40
  9. package/data/_indexes/activity-feed.json +240 -240
  10. package/data/_indexes/catalog-summaries.json +3 -3
  11. package/data/_indexes/currency.json +64 -64
  12. package/data/_indexes/jurisdiction-map.json +31 -158
  13. package/data/_indexes/recipes.json +1 -1
  14. package/data/_indexes/section-offsets.json +510 -510
  15. package/data/_indexes/summary-cards.json +33 -33
  16. package/data/_indexes/token-budget.json +200 -200
  17. package/data/atlas-ttps.json +7 -7
  18. package/data/attack-techniques.json +5 -5
  19. package/data/framework-control-gaps.json +3 -3
  20. package/lib/auto-discovery.js +15 -9
  21. package/lib/collectors/library-author.js +26 -9
  22. package/lib/collectors/secrets.js +8 -1
  23. package/lib/cvss.js +108 -0
  24. package/lib/lint-skills.js +6 -1
  25. package/lib/playbook-runner.js +17 -4
  26. package/lib/prefetch.js +97 -5
  27. package/lib/refresh-external.js +25 -13
  28. package/lib/schemas/manifest.schema.json +1 -1
  29. package/lib/schemas/skill-frontmatter.schema.json +1 -1
  30. package/lib/validate-indexes.js +5 -0
  31. package/lib/version-pins.js +3 -3
  32. package/manifest-snapshot.json +2 -2
  33. package/manifest-snapshot.sha256 +1 -1
  34. package/manifest.json +124 -124
  35. package/orchestrator/pipeline.js +16 -4
  36. package/package.json +1 -1
  37. package/sbom.cdx.json +170 -140
  38. package/scripts/build-indexes.js +12 -1
  39. package/scripts/builders/catalog-summaries.js +1 -1
  40. package/scripts/builders/recipes.js +1 -1
  41. package/scripts/check-sbom-currency.js +76 -14
  42. package/scripts/refresh-sbom.js +1 -1
  43. package/scripts/run-e2e-scenarios.js +48 -17
  44. package/scripts/sync-package-description.js +74 -0
  45. package/scripts/verify-shipped-tarball.js +18 -7
  46. package/skills/age-gates-child-safety/skill.md +3 -3
  47. package/skills/ai-attack-surface/skill.md +4 -4
  48. package/skills/ai-c2-detection/skill.md +5 -5
  49. package/skills/api-security/skill.md +2 -2
  50. package/skills/attack-surface-pentest/skill.md +4 -4
  51. package/skills/cloud-security/skill.md +3 -3
  52. package/skills/compliance-theater/skill.md +3 -3
  53. package/skills/container-runtime-security/skill.md +3 -3
  54. package/skills/coordinated-vuln-disclosure/skill.md +2 -2
  55. package/skills/defensive-countermeasure-mapping/skill.md +3 -3
  56. package/skills/dlp-gap-analysis/skill.md +5 -5
  57. package/skills/exploit-scoring/skill.md +2 -2
  58. package/skills/framework-gap-analysis/skill.md +4 -4
  59. package/skills/fuzz-testing-strategy/skill.md +2 -2
  60. package/skills/incident-response-playbook/skill.md +3 -3
  61. package/skills/mcp-agent-trust/skill.md +2 -2
  62. package/skills/mlops-security/skill.md +3 -3
  63. package/skills/ot-ics-security/skill.md +3 -3
  64. package/skills/policy-exception-gen/skill.md +3 -3
  65. package/skills/pqc-first/skill.md +2 -2
  66. package/skills/rag-pipeline-security/skill.md +4 -4
  67. package/skills/ransomware-response/skill.md +2 -2
  68. package/skills/sector-energy/skill.md +2 -2
  69. package/skills/sector-federal-government/skill.md +2 -2
  70. package/skills/sector-financial/skill.md +4 -4
  71. package/skills/sector-healthcare/skill.md +3 -3
  72. package/skills/security-maturity-tiers/skill.md +1 -1
  73. package/skills/skill-update-loop/skill.md +6 -6
  74. package/skills/supply-chain-integrity/skill.md +2 -2
  75. package/skills/threat-model-currency/skill.md +8 -8
  76. package/skills/threat-modeling-methodology/skill.md +2 -2
  77. package/skills/webapp-security/skill.md +2 -2
  78. package/skills/zeroday-gap-learn/skill.md +3 -3
  79. package/sources/validators/cve-validator.js +27 -18
@@ -43,7 +43,7 @@ forward_watch:
43
43
  - Unified Kill Chain successor revision (Pols, post-v3.0)
44
44
  - LINDDUN-GO and LINDDUN-PRO updates incorporating LLM privacy threats
45
45
  - PASTA v2 updates incorporating AI/ML application threats
46
- last_threat_review: "2026-05-11"
46
+ last_threat_review: "2026-06-10"
47
47
  discovery_mode: "standalone" # operator-reached via `exceptd brief threat-modeling-methodology` or `exceptd ask`; not chained into any playbook's direct.skill_chain by design
48
48
  ---
49
49
 
@@ -132,7 +132,7 @@ Threat-modelling methodologies are *consumers* of the TTP catalog, not contribut
132
132
  | Cyber Kill Chain | Linear 7-stage intrusion timeline | Per stage: ATT&CK TTPs | Cloud-native / serverless / AI-pipeline scenarios fit the timeline poorly; lateral movement assumptions break in ephemeral compute. |
133
133
  | Diamond Model | Adversary–capability–infrastructure–victim diamond | Per intrusion event: TTPs become adversary capabilities; pivot to other diamonds | Built for IR / SOC, not for design-phase threat modelling — pair with STRIDE/PASTA during design and Diamond during operate phase. |
134
134
  | MITRE Unified Kill Chain (v3.0, 2024) | 18 phases spanning initial access through objectives | Per phase: ATLAS and ATT&CK TTPs assigned to phases that cover both classical and AI-augmented attacks | Most comprehensive single methodology, but weak on privacy threats — pair with LINDDUN. |
135
- | AI-system threat modeling (composite) | Augmented DFD with AI actors and AI trust boundaries | Full ATLAS v5.6.0 catalogue (every `AML.T*` key in `data/atlas-ttps.json`) | Methodology not yet standardised — this skill operationalises it. |
135
+ | AI-system threat modeling (composite) | Augmented DFD with AI actors and AI trust boundaries | Full ATLAS v2026.05 catalogue (every `AML.T*` key in `data/atlas-ttps.json`) | Methodology not yet standardised — this skill operationalises it. |
136
136
  | Agent-based threat modeling | Actor graph with autonomous agents, MCP plugins, tool-call boundaries | CVE-2026-30615 (MCP RCE), CVE-2025-53773 (prompt-injection RCE), AML.T0051, AML.T0096 | Methodology not yet standardised — this skill operationalises it. |
137
137
 
138
138
  The truth set for any composite model is: every `AML.T*` key in `data/atlas-ttps.json`, plus every `attack_refs` entry across every CVE in `data/cve-catalog.json`, plus the CWE root-cause classes in `data/cwe-catalog.json`. A model that does not address each, or document a reasoned exclusion for each, is non-current by construction (and should be re-run through `threat-model-currency`).
@@ -65,7 +65,7 @@ d3fend_refs:
65
65
  - D3-MFA
66
66
  forward_watch:
67
67
  - NGINX Rift CVE-2026-42945 (disclosed 2026-05-13, source depthfirst) — KEV-watch predicted CISA KEV listing by 2026-05-29; AI-assisted discovery angle; track for active-exploitation confirmation and patch advisory affecting front-door web app deployments
68
- last_threat_review: "2026-05-11"
68
+ last_threat_review: "2026-06-10"
69
69
  discovery_mode: "standalone" # operator-reached via `exceptd brief webapp-security` or `exceptd ask`; not chained into any playbook's direct.skill_chain by design
70
70
  ---
71
71
 
@@ -105,7 +105,7 @@ Webapps still ship CWE-79 (Cross-Site Scripting), CWE-89 (SQL Injection), and CW
105
105
 
106
106
  ---
107
107
 
108
- ## TTP Mapping (MITRE ATT&CK Enterprise + ATLAS v5.6.0)
108
+ ## TTP Mapping (MITRE ATT&CK Enterprise + ATLAS v2026.05)
109
109
 
110
110
  | TTP ID | Technique | Webapp Manifestation | CWE Root-Causes | Framework Coverage |
111
111
  |---|---|---|---|---|
@@ -23,7 +23,7 @@ forward_watch:
23
23
  - New ATLAS TTP additions in each ATLAS release
24
24
  - Framework updates that close previously open gaps
25
25
  - Vendor advisories for MCP/AI tool supply chain CVEs
26
- last_threat_review: "2026-05-18"
26
+ last_threat_review: "2026-06-10"
27
27
  discovery_mode: "standalone" # operator-reached via `exceptd brief zeroday-gap-learn` or `exceptd ask`; not chained into any playbook's direct.skill_chain by design
28
28
  ---
29
29
 
@@ -79,7 +79,7 @@ This skill is meta — it does not pin to a single TTP class. The learning loop
79
79
  | Input Catalog | Role in the Learning Loop |
80
80
  |---|---|
81
81
  | `data/cve-catalog.json` | The CVE-level corpus: each entry is a candidate lesson input. New entries trigger a new loop run. |
82
- | `data/atlas-ttps.json` (MITRE ATLAS v5.6.0) | The AI/ML TTP taxonomy. Attack-vector extraction maps the CVE's mechanism to an ATLAS ID (e.g., AML.T0096 for SesameOp AI-as-C2). |
82
+ | `data/atlas-ttps.json` (MITRE ATLAS v2026.05) | The AI/ML TTP taxonomy. Attack-vector extraction maps the CVE's mechanism to an ATLAS ID (e.g., AML.T0096 for SesameOp AI-as-C2). |
83
83
  | `data/framework-control-gaps.json` | The control-gap corpus. Framework-coverage assessment writes into this file via new entries or `status` updates. |
84
84
  | `data/zeroday-lessons.json` | The output corpus. Each completed loop produces one entry here — the durable artifact of the lesson. |
85
85
 
@@ -369,7 +369,7 @@ Run through each applicable framework:
369
369
  - CIS Controls v8 (which control?)
370
370
  - ASD Essential 8 (which mitigation?)
371
371
  - ISO 27001:2022 (which control?)
372
- - MITRE ATLAS v5.6.0 (which TTP? Is it covered?)
372
+ - MITRE ATLAS v2026.05 (which TTP? Is it covered?)
373
373
 
374
374
  For each: Covered (adequate) / Covered (insufficient) / Missing entirely
375
375
 
@@ -38,6 +38,8 @@ const NVD_API = 'https://services.nvd.nist.gov/rest/json/cves/2.0?cveId=';
38
38
  const KEV_FEED = 'https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json';
39
39
  const EPSS_API = 'https://api.first.org/data/v1/epss?cve=';
40
40
  const REQUEST_TIMEOUT_MS = 10_000;
41
+
42
+ const { selectNvdCvss, cvssVersionOf } = require('../../lib/cvss');
41
43
  const EPSS_DRIFT_THRESHOLD = 0.05; // |Δscore| or |Δpercentile| > 0.05 flags drift
42
44
  const USER_AGENT = 'exceptd-security/cve-validator (+https://exceptd.com)';
43
45
 
@@ -93,22 +95,19 @@ function resetKevCache() {
93
95
  }
94
96
 
95
97
  function extractNvdCvss(nvdJson) {
96
- // NVD response: vulnerabilities[0].cve.metrics.cvssMetricV31[0].cvssData
98
+ // NVD response: vulnerabilities[0].cve.metrics.cvssMetricV3x/V2[].cvssData.
99
+ // Prefer the newest CVSS version present (Primary within it) and normalize a
100
+ // bare v2 vector to its canonical prefix — NVD tags the legacy v2 metric
101
+ // "Primary" on pre-v3 CVEs over a v3.1 "Secondary", so selecting by type
102
+ // alone would report a stale v2 score as the upstream value.
97
103
  const vuln = nvdJson?.vulnerabilities?.[0]?.cve;
98
104
  if (!vuln) return null;
99
- const metrics = vuln.metrics || {};
100
- const ordered = [
101
- ...(metrics.cvssMetricV31 || []),
102
- ...(metrics.cvssMetricV30 || []),
103
- ...(metrics.cvssMetricV2 || []),
104
- ];
105
- // Prefer Primary type if present
106
- const primary = ordered.find(m => m.type === 'Primary') || ordered[0];
107
- if (!primary?.cvssData) return null;
105
+ const up = selectNvdCvss(vuln.metrics);
106
+ if (!up) return null;
108
107
  return {
109
- score: typeof primary.cvssData.baseScore === 'number' ? primary.cvssData.baseScore : null,
110
- vector: primary.cvssData.vectorString || null,
111
- source: primary.source || null,
108
+ score: up.baseScore,
109
+ vector: up.vector,
110
+ source: up.source,
112
111
  };
113
112
  }
114
113
 
@@ -270,13 +269,23 @@ async function validateCve(cveId, localEntry) {
270
269
  }
271
270
 
272
271
  // --- Compare CVSS (only if NVD reachable & has data) ---
273
- if (cveFoundInNvd && fetched.cvss_score !== null && local.cvss_score !== null) {
274
- if (Math.abs(fetched.cvss_score - local.cvss_score) > 0.05) {
272
+ // Guard against cross-version downgrades: NVD often carries only a legacy v2
273
+ // metric for older CVEs while the catalog is curated to CVSS:3.1. Surfacing
274
+ // (and, on `refresh --apply`, writing) the lower v2 score/vector over a
275
+ // curated v3.x value is a downgrade, not a drift. Mirror the cache path's
276
+ // suppression (lib/refresh-external.js nvdDiffFromCache) so the live and
277
+ // cache refresh paths converge; a same-version re-score still flows through.
278
+ const localCvssVersion = cvssVersionOf(local.cvss_vector);
279
+ const fetchedCvssVersion = cvssVersionOf(fetched.cvss_vector);
280
+ const cvssIsDowngrade =
281
+ fetchedCvssVersion != null && localCvssVersion != null && fetchedCvssVersion < localCvssVersion;
282
+ if (cveFoundInNvd && !cvssIsDowngrade) {
283
+ if (fetched.cvss_score !== null && local.cvss_score !== null &&
284
+ Math.abs(fetched.cvss_score - local.cvss_score) > 0.05) {
275
285
  pushDiscrepancy(discrepancies, 'cvss_score', local.cvss_score, fetched.cvss_score, 'high');
276
286
  }
277
- }
278
- if (cveFoundInNvd && fetched.cvss_vector && local.cvss_vector) {
279
- if (fetched.cvss_vector !== local.cvss_vector) {
287
+ if (fetched.cvss_vector && local.cvss_vector &&
288
+ fetched.cvss_vector !== local.cvss_vector) {
280
289
  pushDiscrepancy(discrepancies, 'cvss_vector', local.cvss_vector, fetched.cvss_vector, 'medium');
281
290
  }
282
291
  }