@blamejs/exceptd-skills 0.13.19 → 0.13.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +72 -0
- package/data/_indexes/_meta.json +6 -6
- package/data/attack-techniques.json +2 -3
- package/data/cve-catalog.json +301 -3792
- package/data/framework-control-gaps.json +168 -504
- package/data/zeroday-lessons.json +5 -3029
- package/lib/canonical-eq.js +88 -0
- package/lib/cve-regression-watcher.js +130 -9
- package/lib/gap-detectors.js +555 -0
- package/lib/source-advisories.js +9 -34
- package/lib/version-pins.js +73 -0
- package/lib/xml-tokenizer.js +344 -0
- package/manifest.json +44 -44
- package/package.json +4 -3
- package/sbom.cdx.json +108 -33
- package/scripts/audit-catalog-gaps.js +74 -13
- package/scripts/check-catalog-gap-budget.js +133 -0
- package/scripts/check-test-coverage.js +16 -18
- package/scripts/predeploy.js +14 -0
- package/scripts/refresh-upstream-catalogs.js +13 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,77 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.13.21 — 2026-05-19
|
|
4
|
+
|
|
5
|
+
Seven new catalog-gap detection classes wired into the predeploy gate. The v0.13.19 detector covered missing-context / dangling-ref / draft-debt; the v0.13.20 audit confirmed that left genuine gap classes unsurfaced. v0.13.21 adds the seven cross-cutting classes the prior detector missed and wires them into a budget gate that runs alongside the existing tests + predeploy gates.
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
|
|
9
|
+
**Seven new detection classes in `lib/gap-detectors.js`:**
|
|
10
|
+
|
|
11
|
+
- **content-quality** — fields present but content weak. Catches: vector text < 50 chars (likely a stub), placeholder-language sentinels (TBD / TKTK / "pending operator curation" / "[]"), KEV-listed entries with empty vendor_advisories, name-repeated-as-description.
|
|
12
|
+
- **temporal-staleness** — time-based decay. Catches: source_verified > 180d old, last_updated > 365d, CISA-KEV due-date passed without remediation status, epss_date > 90d.
|
|
13
|
+
- **logical-consistency** — internal-state contradictions that pass schema validation but don't make sense. Catches: `cisa_kev:true + cisa_kev_date:null`, `live_patch_available:true + live_patch_tools:[]`, `ai_discovered:true + attribution_note < 30 chars`, `active_exploitation:"confirmed" + verification_sources.length < 2`, `rwep_score declared + rwep_factors empty`.
|
|
14
|
+
- **cross-ref-completeness** — bidirectional reference checks. The v0.13.19 dangling-ref class only verified the forward direction (CVE→CWE resolves); v0.13.21 also verifies the back-reference is present (CWE.evidence_cves includes the citing CVE). Same logic for ATT&CK.cve_refs and framework-control-gaps.evidence_cves.
|
|
15
|
+
- **schema-evolution** — required-since-version checks. Fields the schema requires today were optional on entries added in older releases. Surfaces pre-existing entries the operator should backfill (e.g. pre-v0.12.36 CVEs lacking the `ai_discovered` boolean).
|
|
16
|
+
- **operator-action-sla** — un-curated auto-imports older than the SLA window. Defaults: 60d for `_auto_imported`, 90d for `_draft`.
|
|
17
|
+
- **unused-orphan** — auto-imported catalog entries that no skill / playbook / CVE references. Operator-curated entries are exempt (intentional content); `forward_looking:true` entries are exempt (intentional forward-look content).
|
|
18
|
+
|
|
19
|
+
**`scripts/check-catalog-gap-budget.js` + predeploy gate.** New predeploy gate runs the seven extended detectors and asserts every class is within its documented budget. Mirrors the budget enforced by `tests/shipped-catalog-integrity.test.js` so a regression surfaces in BOTH the gate-summary table AND the test output. Predeploy summary now reports 16 gates (was 15).
|
|
20
|
+
|
|
21
|
+
**`tests/gap-detectors.test.js`** — 22 per-detector tests pin each of the seven classes against synthetic catalog inputs. Each pin asserts the detector fires on the shape it's designed to catch AND does NOT fire on the inverse shape (no false positives).
|
|
22
|
+
|
|
23
|
+
### Bugs
|
|
24
|
+
|
|
25
|
+
**T1574 ATT&CK back-ref synced.** v0.13.20's CTFMON-mapping fix added T1574 to `BUG-2026-NIGHTMARE-ECLIPSE-GREENPLASMA.attack_refs[]`, but the reverse-refs pass didn't run before sign + sbom + commit, so `attack-techniques.T1574.cve_refs[]` didn't pick up the back-ref. The v0.13.21 cross-ref-completeness detector surfaced this on first run — fixed via `npm run refresh-reverse-refs`.
|
|
26
|
+
|
|
27
|
+
### Internal
|
|
28
|
+
|
|
29
|
+
- `scripts/audit-catalog-gaps.js` CLI extended: `--class <name>` accepts the seven new class names (`content-quality`, `temporal-staleness`, `logical-consistency`, `cross-ref-completeness`, `schema-evolution`, `operator-action-sla`, `unused-orphan`) for scoped audits. JSON + pretty output include an `extended_findings` section grouped by class, with `totals.extended` counts.
|
|
30
|
+
- `tests/shipped-catalog-integrity.test.js` includes a new budget pin for the seven extended classes — a future PR that worsens any class beyond budget fires the test.
|
|
31
|
+
- npm alias: `npm run audit-catalog-gap-budget` runs the budget gate standalone (operator-facing convenience).
|
|
32
|
+
- Current shipped-catalog snapshot: content-quality=10, temporal-staleness=255, logical-consistency=0, cross-ref-completeness=0, schema-evolution=0, operator-action-sla=0, unused-orphan=1342. The non-zero classes are operator-curation work items surfaced honestly by the new detectors.
|
|
33
|
+
|
|
34
|
+
## 0.13.20 — 2026-05-19
|
|
35
|
+
|
|
36
|
+
Root-cause refactor addressing every audit class surfaced by the v0.13.17–v0.13.19 self-audit (no-MVP violations, regex-where-logic-is-required, symptom patches, coincidence-pinning tests, uncaught bugs). The audit found I had been patching symptoms instead of fixing root causes; v0.13.20 fixes the actual issues and lets the audit tell the truth about catalog state.
|
|
37
|
+
|
|
38
|
+
### Features
|
|
39
|
+
|
|
40
|
+
**Real XML tokenizer replaces the regex-based RSS/Atom parser.** `lib/xml-tokenizer.js` is a proper streaming parser with CDATA handling, XML-namespace support (local-name matching), self-closing element handling, HTML-entity + numeric-character-reference decoding, and observable parse errors (the old regex parser returned `[]` silently on malformed input). `lib/source-advisories.js#parseRssAtom` now delegates to the tokenizer; the upstream contract is preserved. Failure modes the regex parser silently dropped (namespaced Atom feeds, CDATA-wrapped HTML titles, multi-line content, unterminated elements at EOF) are now explicit test cases (`tests/xml-tokenizer.test.js`).
|
|
41
|
+
|
|
42
|
+
**Canonical-form deep equality replaces JSON.stringify in diff-coverage.** `lib/canonical-eq.js` provides sorted-key recursive equality for catalog change detection. Pre-v0.13.20 the diff-coverage gate compared `JSON.stringify(before.iocs) !== JSON.stringify(after.iocs)` — non-canonical, false-positives on key-order rearrangement. The symptom was patched twice (`_auto_imported` skip in v0.13.17, `_iocs_stub` skip in v0.13.19). v0.13.20 fixes the comparator. The `_iocs_stub` skip rule is removed.
|
|
43
|
+
|
|
44
|
+
**Content-pattern matching in `lib/cve-regression-watcher.js`.** Pre-v0.13.20 the watcher fired only when a poller diff carried an explicit `CVE-YYYY-NNN` identifier. If a researcher's writeup announced "the 2020 fix is silently reverted" without typing the CVE ID, the watcher missed entirely. v0.13.20 adds three signal layers: historical-regression language patterns (`silently reverted`, `re-exploitable`, `same primitive as`), named-researcher patterns (Nightmare-Eclipse / Project Zero / Big Sleep / Forshaw / Horn / Ormandy), and tracked-component tokens (`cldflt.sys`, `HsmOsBlockPlaceholderAccess`, `ssh-keysign`, `CTFMON`). Diffs that lack a historical CVE-ID but trip the signals surface as `action: "content-only-investigate"` for operator triage.
|
|
45
|
+
|
|
46
|
+
**`forward_looking: true` schema field replaces blanket `_gap_skip` on framework-control-gaps.** v0.13.19 used per-entry `_gap_skip: { fields: ["evidence_cves"] }` on 84 framework gaps as a class-level exemption — opaque to operators reading the JSON. v0.13.20 promotes the exemption to a first-class schema field (`forward_looking: true` + `forward_looking_reason`) that the audit honors. The `_gap_skip` annotations on those 84 entries are removed in lockstep.
|
|
47
|
+
|
|
48
|
+
**`lib/version-pins.js` — single source of truth for MITRE pinned versions.** Pre-v0.13.20 the ATLAS version pin lived in 33+ files in lockstep. A bump (v5.4.0 → v5.6.0) required a regex sweep that incidentally touched dates in unrelated paragraphs. v0.13.20 reads ATLAS + ATT&CK version from `data/atlas-ttps.json._meta.atlas_version` and `data/attack-techniques.json._meta.attack_version` via the new module. Downstream tests + doc-currency checks consume through it. Future bumps refresh one JSON field; the module propagates.
|
|
49
|
+
|
|
50
|
+
**SPEC-driven refresher.** `scripts/refresh-upstream-catalogs.js` now imports the audit `SPEC.<catalog>.required_context` lists from `scripts/audit-catalog-gaps.js` instead of carrying parallel hardcoded field arrays. The v0.13.18→19 episode where the refresher backfilled `description_full` + `platforms` but forgot `description` + `tactic` (and the audit had to surface 106 ATT&CK rows still missing context) is structurally impossible now — one truth source.
|
|
51
|
+
|
|
52
|
+
**`tests/shipped-catalog-integrity.test.js` — new test file.** Splits the live-catalog assertions out of `tests/audit-catalog-gaps.test.js` (which now exercises detector logic against synthetic inputs only). Live invariants policed here: zero dangling cross-catalog refs, no `_gap_skip` stragglers on framework gaps that should be `forward_looking`, and a budget-per-catalog for missing-context findings (per-catalog snapshot count; a future PR that worsens any catalog without acknowledgement fires the test).
|
|
53
|
+
|
|
54
|
+
**`tests/refresher-fixture-roundtrip.test.js` — new test file.** Each upstream refresher gets a synthetic-fixture round-trip pin. Pre-v0.13.20 the only refresher coverage was a `typeof` check on the exported function; a refresher that regressed to "return early without writing" would have passed. Now CSAF index parsing, ATT&CK STIX shape, ICS-attack registry presence, RSS / Atom parse contract, and the canonical RFC-entry tag set are all pinned independently.
|
|
55
|
+
|
|
56
|
+
### Bugs (every audit class addressed)
|
|
57
|
+
|
|
58
|
+
**Class 1.1, 1.3 — stub fills stripped.** 291 CVE entries had stub IoCs (`"IOC list pending operator curation"`) auto-written by the v0.13.17 KEV bulk-import + v0.13.19 gap-fix passes; 252 zeroday-lessons entries had a generic `NEW-CTRL-001` baseline as their only `new_control_requirements`. Both fields stripped back to absent. The audit now reports the honest curation backlog instead of letting the catalog pass with placeholder content. Per-CVE IoC + per-primitive control curation is operator work going forward.
|
|
59
|
+
|
|
60
|
+
**Class 1.2, 5.15 — forward-looking framework gaps use a schema field.** 84 entries with `_gap_skip` converted to `forward_looking: true` + a `forward_looking_reason` prose field. The audit SPEC honors the schema field. `tests/shipped-catalog-integrity.test.js` pins that no `_gap_skip.evidence_cves` stragglers remain.
|
|
61
|
+
|
|
62
|
+
**Class 2.7 — CTFMON mapping corrected.** GreenPlasma's `attack_refs` was T1574.012 (Hijack Execution Flow: COR_PROFILER — .NET CLR profiler hijack, wrong primitive). v0.13.20 changes to T1574 base (Hijack Execution Flow) + T1068 (Exploitation for Privilege Escalation) with an `_attack_refs_correction_note` explaining the prior mapping was lazy.
|
|
63
|
+
|
|
64
|
+
**Class 4.12 — audit-test split.** `tests/audit-catalog-gaps.test.js` exercises detector logic only (synthetic inputs); `tests/shipped-catalog-integrity.test.js` carries the live-catalog assertions. A future regression to detector logic vs a future change to catalog data are now distinguishable.
|
|
65
|
+
|
|
66
|
+
**Class 5.14 — test-baseline drift investigated.** The 1028→1040 bump over 3 releases was driven by legitimate new test files (intake-coverage, regression-watcher, gap-detector, refresher-fixture, etc.), not by the gate being misused. Baseline grow-threshold convention preserved with an explanatory `notes` field in `tests/.test-count-baseline.json`.
|
|
67
|
+
|
|
68
|
+
### Internal
|
|
69
|
+
|
|
70
|
+
- `lib/canonical-eq.js`, `lib/xml-tokenizer.js`, `lib/version-pins.js` shipped under `lib/` (in the tarball file-allowlist).
|
|
71
|
+
- 5 new test files: `canonical-eq.test.js`, `xml-tokenizer.test.js`, `version-pins.test.js`, `shipped-catalog-integrity.test.js`, `refresher-fixture-roundtrip.test.js`, `refresher-spec-coupling.test.js`.
|
|
72
|
+
- `scripts/check-test-coverage.js#extractCveIocChanges` uses `canonicalEqual` for the iocs diff; the `_iocs_stub` skip rule is removed. `_auto_imported` skip rule retained (true positive — bulk-imported stub IoCs are intake-class events, not operator curation).
|
|
73
|
+
- 1377 tests / 1364 passing in this commit; remaining failures are the version + path checks fixed in the next commit hash chain.
|
|
74
|
+
|
|
3
75
|
## 0.13.19 — 2026-05-19
|
|
4
76
|
|
|
5
77
|
Automated catalog gap-detection + closure of every gap surfaced by the new detector. After the v0.13.18 bulk expansion grew six catalogs to comparable scale, the audit at T+1 day showed real holes (51 CVEs without IoCs, 120 RFCs without abstracts, 106 ATT&CK techniques without context fields, 84 framework gaps without evidence). This release ships the detector permanently and closes every hole it found.
|
package/data/_indexes/_meta.json
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema_version": "1.1.0",
|
|
3
|
-
"generated_at": "2026-05-
|
|
3
|
+
"generated_at": "2026-05-19T20:58:49.735Z",
|
|
4
4
|
"generator": "scripts/build-indexes.js",
|
|
5
5
|
"source_count": 54,
|
|
6
6
|
"source_hashes": {
|
|
7
|
-
"manifest.json": "
|
|
7
|
+
"manifest.json": "b8676a67b642f623974dccf3ba0f1df95836541b7c1dcd0c63cef2b71fa1a88a",
|
|
8
8
|
"data/atlas-ttps.json": "d296c1d3e71807c9279b731f047e57796e85137f186586743a8cdad214b408f9",
|
|
9
|
-
"data/attack-techniques.json": "
|
|
10
|
-
"data/cve-catalog.json": "
|
|
9
|
+
"data/attack-techniques.json": "49b6010b317edd219def135171ea8f3b1bbf1e00e9c5a08bf7237215ff54e2c3",
|
|
10
|
+
"data/cve-catalog.json": "a09c83af3f9679a7ea73935726a1ff9de2cab94b4ab6321fc017fc147747d7c3",
|
|
11
11
|
"data/cwe-catalog.json": "c56e74b8c9290583b1d6fdd21b54bd65a254c58890c5f683379788ca7b080e9d",
|
|
12
12
|
"data/d3fend-catalog.json": "4271102f8c38999444bcd981c1cf5feb4ad09f8c0b1d9b79df3f1a82f4fb50f0",
|
|
13
13
|
"data/dlp-controls.json": "d2406c482dddd30e49203879999dc4b3a7fd4d0494d6a61d86b91ee76415df19",
|
|
14
14
|
"data/exploit-availability.json": "ec2656f0d9a893610e27b43eb6035fe9b18e057c9f6dfaac7e7d4959bbcbb795",
|
|
15
|
-
"data/framework-control-gaps.json": "
|
|
15
|
+
"data/framework-control-gaps.json": "b63fe398c3de068093871e8bbca11e16b6567fb15482648d0bbce06939c34104",
|
|
16
16
|
"data/global-frameworks.json": "9ba563a85f7f8d6c3c957de64945e20925a89d0ed6ea6fc561cf093811acf558",
|
|
17
17
|
"data/rfc-references.json": "926ea25892e052fc6a8b9952afc1d8e2bd06c4aec223a1a7aa79ef1dfd7b7bb5",
|
|
18
|
-
"data/zeroday-lessons.json": "
|
|
18
|
+
"data/zeroday-lessons.json": "7242a7349ac79a74813bf2b7486b6000c0c877e71cec17e2d68df33bc4007b93",
|
|
19
19
|
"skills/kernel-lpe-triage/skill.md": "08b3e9815ba481c57c80f5fc0ccbf5bb7cbb41f570c235ba6ff9596b8c07354d",
|
|
20
20
|
"skills/ai-attack-surface/skill.md": "6ff82cd5e805a29b694a71ffbeba22e78966249da921706f3256fa4319e402fc",
|
|
21
21
|
"skills/mcp-agent-trust/skill.md": "bf3ded40e84443400c9bec8634e0d6a14c9633e569d8c2e26f9d5881f8e78dff",
|
|
@@ -1833,6 +1833,7 @@
|
|
|
1833
1833
|
"name": "Hijack Execution Flow",
|
|
1834
1834
|
"version": "v19",
|
|
1835
1835
|
"cve_refs": [
|
|
1836
|
+
"BUG-2026-NIGHTMARE-ECLIPSE-GREENPLASMA",
|
|
1836
1837
|
"CVE-2026-45321"
|
|
1837
1838
|
],
|
|
1838
1839
|
"description_full": "Adversaries may execute their own malicious payloads by hijacking the way operating systems run programs. Hijacking execution flow can be for the purposes of persistence, since this hijacked execution may reoccur over time. Adversaries may also use these mechanisms to elevate privileges or evade defenses, such as application control or other restrictions on execution. There are many ways an adversary may hijack the flow of execution, including by manipulating how the operating system locates programs to be executed. How the operating system locates libraries to be used by a program can also be intercepted. Locations where the operating system looks for programs/resources, such as file directories and in the case of Windows the Registry, could also be poisoned to include malicious payloads.",
|
|
@@ -5474,9 +5475,7 @@
|
|
|
5474
5475
|
"last_verified": "2026-05-19",
|
|
5475
5476
|
"_auto_imported": true,
|
|
5476
5477
|
"_intake_method": "v0.13.18-orphan-fill",
|
|
5477
|
-
"cve_refs": [
|
|
5478
|
-
"BUG-2026-NIGHTMARE-ECLIPSE-GREENPLASMA"
|
|
5479
|
-
],
|
|
5478
|
+
"cve_refs": [],
|
|
5480
5479
|
"description_full": "Adversaries may leverage the COR_PROFILER environment variable to hijack the execution flow of programs that load the .NET CLR. The COR_PROFILER is a .NET Framework feature which allows developers to specify an unmanaged (or external of .NET) profiling DLL to be loaded into each .NET process that loads the Common Language Runtime (CLR). These profilers are designed to monitor, troubleshoot, and debug managed code executed by the .NET CLR.(Citation: Microsoft Profiling Mar 2017)(Citation: Microsoft COR_PROFILER Feb 2013) The COR_PROFILER environment variable can be set at various scopes (system, user, or process) resulting in different levels of influence. System and user-wide environment variable scopes are specified in the Registry, where a [Component Object Model](https://attack.mitre.org/techniques/T1559/001) (COM) object can be registered as a profiler DLL. A process scope COR_PROFILER can also be created in-memory without modifying the Registry. Starting with .NET Framework 4, the profiling DLL does not need to be registered as long as the location of the DLL is specified in the COR_PROFILER_PATH environment variable.(Citation: Microsoft COR_PROFILER Feb 2013) Adversaries may abuse COR_PROFILER to establish persistence that executes a malicious DLL in the context of all .NET processes every time the CLR is invoked. The COR_PROFILER can also be used to elevate privileges (ex: [Bypass User Account Control](https://attack.mitre.org/techniques/T1548/002)) if the victim .NET process executes at a higher permission level, as well as to hook and impair defenses provided by .NET processes.(Citation: RedCanary Mockingbird May 2020)(Citation: Red Canary COR_PROFILER May 2020)(Citation: Almond COR_PROFILER Apr 2019)(Citation: GitHub OmerYa Invisi-Shell)(Citation: subTee .NET Profilers May 2017)",
|
|
5481
5480
|
"platforms": [
|
|
5482
5481
|
"Windows"
|