@blamejs/exceptd-skills 0.13.1 → 0.13.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.
- package/CHANGELOG.md +73 -0
- package/bin/exceptd.js +140 -7
- package/data/_indexes/_meta.json +28 -28
- package/data/_indexes/activity-feed.json +3 -3
- package/data/_indexes/catalog-summaries.json +3 -3
- package/data/_indexes/chains.json +1897 -88
- package/data/_indexes/frequency.json +20 -0
- package/data/_indexes/section-offsets.json +574 -574
- package/data/_indexes/token-budget.json +97 -97
- package/data/atlas-ttps.json +2 -0
- package/data/attack-techniques.json +24 -3
- package/data/cve-catalog.json +96 -29
- package/data/cwe-catalog.json +20 -3
- package/data/framework-control-gaps.json +700 -1
- package/data/zeroday-lessons.json +889 -0
- package/lib/lint-skills.js +54 -1
- package/lib/source-advisories.js +26 -0
- package/manifest.json +62 -62
- package/orchestrator/index.js +155 -3
- package/package.json +1 -1
- package/sbom.cdx.json +50 -39
- package/scripts/check-test-count.js +146 -0
- package/scripts/predeploy.js +16 -0
- package/skills/age-gates-child-safety/skill.md +1 -0
- package/skills/ai-risk-management/skill.md +1 -0
- package/skills/api-security/skill.md +14 -4
- package/skills/cloud-iam-incident/skill.md +1 -1
- package/skills/defensive-countermeasure-mapping/skill.md +1 -0
- package/skills/email-security-anti-phishing/skill.md +15 -4
- package/skills/fuzz-testing-strategy/skill.md +1 -0
- package/skills/mlops-security/skill.md +1 -0
- package/skills/ot-ics-security/skill.md +1 -0
- package/skills/researcher/skill.md +1 -0
- package/skills/sector-energy/skill.md +1 -0
- package/skills/sector-federal-government/skill.md +1 -0
- package/skills/sector-telecom/skill.md +1 -0
- package/skills/skill-update-loop/skill.md +1 -0
- package/skills/threat-model-currency/skill.md +1 -0
- package/skills/threat-modeling-methodology/skill.md +1 -0
- package/skills/webapp-security/skill.md +1 -0
- package/skills/zeroday-gap-learn/skill.md +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,78 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.13.3 — 2026-05-18
|
|
4
|
+
|
|
5
|
+
Audit close-out continuation: the items the prior pass marked for follow-up. Workflow hardening, lint enforcement promoted from warning to hard error, two new operator-facing health checks for the Shai-Hulud lesson controls, and 4 more primary-source pollers covering kernel.org / oss-security / JFrog / CISA.
|
|
6
|
+
|
|
7
|
+
### Security
|
|
8
|
+
|
|
9
|
+
**`refresh.yml` split into two jobs — `refresh-data` (no write credentials) + `open-pr` (contents:write + pull-requests:write + issues:write scoped to PR creation only).** Pre-split a single `refresh` job carried write capability against the repo throughout the long-running data-parse + prefetch + apply + predeploy sequence; a compromise of any of those steps had repo-write access during the whole run. The new shape scopes write capability to the few-second PR-creation window. Data mutations flow between jobs via an upload-artifact / download-artifact bundle. The `refresh-data` checkout now uses `persist-credentials: false`.
|
|
10
|
+
|
|
11
|
+
**`lib/lint-skills.js` Hard Rule #1 body-scan flipped from warning to hard error.** v0.13.2 introduced the body-scan as a warning while the 2 pre-existing violations were triaged. Both are now resolved (`CVE-2024-21762` landed in the catalog with full Hard Rule #1 fields; the placeholder `CVE-2026-21370` reference was removed from `cloud-iam-incident`). The body-scan now errors when a skill cites a CVE not in the catalog. Draft references continue to surface as warnings.
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
**`exceptd doctor --ai-config` audits AI-assistant config-file permissions.** Implements NEW-CTRL-050 from the MAL-2026-SHAI-HULUD-OSS zeroday-lessons entry. Walks `~/.claude`, `~/.cursor`, `~/.codeium`, `~/.aider`, `~/.continue` for sensitive files (`settings.json`, `mcp.json`, `*.mcp_config.json`, `api_key*`, `*.token`, `*.credentials`) and reports any not at mode 0600 on POSIX. On Windows the mode bits aren't load-bearing; each sensitive file is flagged with an info-level "manual ACL review" note. Opt-in via `--ai-config`; doesn't run as part of the default no-flag doctor pass.
|
|
16
|
+
|
|
17
|
+
**`exceptd watchlist --org-scan` probes GitHub for threat-actor repo naming patterns.** Implements NEW-CTRL-052 from the MAL-2026-SHAI-HULUD-OSS zeroday-lessons entry. Queries the GitHub Search API for repos matching the canonical Shai-Hulud / TeamPCP patterns ("A Gift From TeamPCP", "Shai-Hulud", "TeamPCP") scoped to `--org <login>`. Custom patterns via repeatable `--pattern <s>`. Set `GITHUB_TOKEN` env var for private-repo coverage and higher rate limit; without it, public-repo search only.
|
|
18
|
+
|
|
19
|
+
**4 more primary-source advisory pollers.** `lib/source-advisories.js` `FEEDS` grew 4 → 8:
|
|
20
|
+
- `kernel-org` — torvalds/linux master commits atom feed. Catches the CVE-2026-46333 / ssh-keysign-pwn class at T+0, the moment the upstream fix lands. The v0.13.1 post-mortem identified this as the exact venue we missed.
|
|
21
|
+
- `oss-security` — openwall.com `oss-security` mailing list atom feed. Coordinated-disclosure venue; many distro advisories announce CVEs here days before NVD enrichment.
|
|
22
|
+
- `jfrog` — JFrog SecOps research blog feed. npm / PyPI / Maven supply-chain disclosures with CVE assignments (TanStack / Mini Shai-Hulud class).
|
|
23
|
+
- `cisa-current` — CISA cybersecurity advisories feed (federal-vendor coordinated disclosures, separate from KEV which captures only exploited-in-the-wild items).
|
|
24
|
+
|
|
25
|
+
### Bugs
|
|
26
|
+
|
|
27
|
+
**`CVE-2024-21762` (Fortinet FortiOS SSL-VPN preauth RCE) added to catalog.** Was cited in skill prose without a backing catalog entry — surfaced by the v0.13.2 Hard Rule #1 body-scan. Full Hard Rule #1 fields (CVSS 9.8, CISA KEV 2024-02-09, public PoC, confirmed mass exploitation across multiple APT clusters, FortiOS patch versions 7.6.2 / 7.4.7 / 7.2.11 / 7.0.17 / 6.4.16). RWEP 85. Includes the 2025-04 follow-up advisory documenting symlink persistence that survives firmware patching.
|
|
28
|
+
|
|
29
|
+
**`CVE-2026-21370` placeholder reference removed from `skills/cloud-iam-incident/skill.md`.** No record of CVE-2026-21370 in any source; was a class-marker parenthetical for the Azure managed-identity token-replay attack class. Rewritten as "design-class issue, not a single CVE" so the prose still accurately describes the IMDS-token-theft pattern without inventing threat intel.
|
|
30
|
+
|
|
31
|
+
**12 framework-gap forward-orphan references closed.** Each pre-existing orphan got a real gap entry with theater_test per Hard Rule #6: `CIS-Kubernetes-Benchmark-4.2.13`, `CIS-Kubernetes-Benchmark-5.3`, `CIS-Controls-v8-Control6`, `ISO-27001-2022-A.5.15`, `ISO-27001-2022-A.8.13`, `NIST-800-53-IA-2`, `NIST-AI-RMF-MEASURE-2.7`, `OWASP-ML-Top-10-2023-ML06`, `NIS2-Art21-network-security`, `NIS2-Art21-business-continuity`, `PCI-DSS-4.0-5.1`, `AU-ISM-1808`. Gap catalog 130 → 142 entries; orphan count for `framework-control-gaps.json` is now 0.
|
|
32
|
+
|
|
33
|
+
**2 empty-`data_deps` skills fixed.** `api-security` and `email-security-anti-phishing` previously had empty `data_deps` because the bodies referenced no catalog file by name. Each now carries 6 catalog references (atlas-ttps, attack-techniques, cwe-catalog / dlp-controls, d3fend-catalog, framework-control-gaps, rfc-references) threaded through the body in 4 new prose passages each. Every cited ID resolves to a real entry in its respective catalog. `last_threat_review` bumped to 2026-05-18.
|
|
34
|
+
|
|
35
|
+
### Internal
|
|
36
|
+
|
|
37
|
+
- 8 new tests in `tests/v0_13_3-fixes.test.js` covering all 5 phases.
|
|
38
|
+
- Test-count baseline refreshed to match the new test surface.
|
|
39
|
+
- ADVISORIES_SOURCE test-fixture extended to include the 4 new feeds.
|
|
40
|
+
- `tests/source-advisories.test.js` `FEEDS: exactly N feeds` pin updated 4 → 8.
|
|
41
|
+
|
|
42
|
+
## 0.13.2 — 2026-05-18
|
|
43
|
+
|
|
44
|
+
Audit close-out: the remaining v0.13 deferrals from the original 6-domain audit + the v0.13.1 post-mortem follow-ups. Patch-class — additive across CI hardening, lint enforcement, CLI UX, predeploy gates, catalog data cleanup, and skill metadata.
|
|
45
|
+
|
|
46
|
+
### Security
|
|
47
|
+
|
|
48
|
+
**`release.yml` publish job split: `publish-npm` (id-token:write only) + `publish-github-release` (contents:write only).** Pre-v0.13.2 a single `publish` job carried BOTH permissions at once — a compromise of any step in that job (leaked NODE_AUTH_TOKEN, malicious dependency in the runner image, third-party action with elevated trust) had access to the npm provenance signing identity AND repo-write simultaneously. The new shape isolates each permission to the minimum surface that needs it. `publish-github-release` depends on `publish-npm` so the GitHub Release only fires when npm publish succeeded — releases pointing at a tag whose npm publish failed are operator-confusing.
|
|
49
|
+
|
|
50
|
+
### Features
|
|
51
|
+
|
|
52
|
+
**`exceptd watchlist --alerts` 5 patterns now stable.** No change in v0.13.2; documenting that the v0.13.1 patterns are now operationally proven against the post-mortem seeds (`CVE-2026-46333` ssh-keysign-pwn surfacing under `kernel_lpe_with_poc`; `MAL-2026-SHAI-HULUD-OSS` under `supply_chain_family`).
|
|
53
|
+
|
|
54
|
+
**Flag-value did-you-mean across 6 sites.** `run --mode`, `brief --phase`, `run --format`, `attest export --format`, `ci --format`, and orchestrator `report <format>` now surface a Levenshtein-≤2 typo suggestion in the structured error body alongside the accepted-set list. JSON shape: `{ok:false, error, provided, accepted, did_you_mean:["..."]}`. Example: `brief library-author --phase goven` → `did_you_mean: ["govern"]`.
|
|
55
|
+
|
|
56
|
+
**`lib/lint-skills.js` Hard Rule #1 body-scan.** Every `CVE-* / MAL-*` reference in skill prose is now resolved against the canonical catalog. Missing-from-catalog surfaces as a WARNING in v0.13.2 (will hard-fail in v0.14.0); `_draft:true` references surface as WARNING. The forcing function lands; pre-existing violations on `ransomware-response` (CVE-2024-21762) and `cloud-iam-incident` (CVE-2026-21370) don't block the release but are now visible in every lint run.
|
|
57
|
+
|
|
58
|
+
**`scripts/check-test-count.js` — new 15th predeploy gate.** Static-counts `test(` declarations across `tests/*.test.js` and refuses shrinkage beyond the configured tolerance (default 1). Baseline pinned in `tests/.test-count-baseline.json`. Catches accidentally-deleted test files / mass-skip mistakes that the lint + diff-coverage gates wouldn't surface. Initial baseline 924 declarations across 94 files; bump with `--update-baseline` on releases that legitimately add many tests.
|
|
59
|
+
|
|
60
|
+
**Skill `discovery_mode: standalone` frontmatter field.** 16 skills that are intentionally reached via `exceptd brief <name>` or `exceptd ask` rather than playbook `skill_chain` now carry the explicit marker. Closes the v0.12 audit gap that flagged these as "unreferenced" — operator intent now explicit. Affected: `age-gates-child-safety`, `ai-risk-management`, `defensive-countermeasure-mapping`, `email-security-anti-phishing`, `fuzz-testing-strategy`, `mlops-security`, `ot-ics-security`, `researcher`, `sector-energy`, `sector-federal-government`, `sector-telecom`, `skill-update-loop`, `threat-model-currency`, `threat-modeling-methodology`, `webapp-security`, `zeroday-gap-learn`.
|
|
61
|
+
|
|
62
|
+
### Bugs
|
|
63
|
+
|
|
64
|
+
**14 still-draft CVEs flipped to verified.** Each got a matching `zeroday-lessons.json` entry (the AGENTS.md rule #6 requirement) and had `_draft` removed: `CVE-2024-3154` (CRI-O kernel-module load), `CVE-2023-43472` (MLflow path-traversal), `CVE-2020-10148` (SUNBURST), `CVE-2023-3519` (Citrix NetScaler unauth RCE), `CVE-2024-1709` (ConnectWise ScreenConnect), `CVE-2026-20182` (Cisco SD-WAN), `CVE-2024-40635` (containerd integer overflow), `CVE-2026-30623` (Anthropic MCP SDK stdio injection), `CVE-2025-12686` (Synology BeeStation Pwn2Own), `CVE-2025-62847` / `CVE-2025-62848` / `CVE-2025-62849` (QNAP QTS DEVCORE chain), `CVE-2025-59389` (QNAP Hyper Data Protector), `CVE-2025-11837` (QNAP Malware Remover). Three new control requirements introduced where the CVE surfaced a novel class: `NEW-CTRL-053` MCP-SERVER-CONFIG-ALLOWLIST, `NEW-CTRL-054` BACKUP-TIER-NETWORK-ISOLATION, `NEW-CTRL-055` SECURITY-TOOL-INTEGRITY-VERIFICATION. Catalog now 37/39 entries verified; 2 remaining drafts are quarantined / embargoed placeholders.
|
|
65
|
+
|
|
66
|
+
**8 framework-gap forward-orphan refs cleaned up.** The v0.13.0 Hard Rule #5 backfill surfaced 8 framework-control gap IDs cited by CVE entries' `framework_control_gaps` field but missing from `framework-control-gaps.json`. All 8 added with theater_test blocks per Hard Rule #6: `NIST-800-53-SC-39` (Process Isolation), `ISO-27001-2022-A.8.22` (Segregation of networks), `CIS-Kubernetes-Benchmark-5.7` (Network Policies), `NIST-800-218-SSDF-PW.4` (Reuse Existing, Well-Secured Software), `NIST-800-53-SR-3` (Supply Chain Controls), `SLSA-v1.0-Source-L3`, `NIST-AI-RMF-MAP-3.4`, `OWASP-Top-10-2021-A06`. Gap catalog 122 → 130 entries.
|
|
67
|
+
|
|
68
|
+
**`release.yml` CHANGELOG-extraction fallback now emits `::warning::`.** Surfaces the parse failure on the run page rather than silently shipping a generic body.
|
|
69
|
+
|
|
70
|
+
### Internal
|
|
71
|
+
|
|
72
|
+
- 11 new tests in `tests/v0_13_2-fixes.test.js`. Test count baseline 924 (initial pin).
|
|
73
|
+
- Predeploy gate count 14 → 15.
|
|
74
|
+
- `refresh.yml` split-checkout pattern (persist-credentials hardening) deferred to v0.14 — needs peter-evans/create-pull-request auth-mode research first.
|
|
75
|
+
|
|
3
76
|
## 0.13.1 — 2026-05-17
|
|
4
77
|
|
|
5
78
|
Threat-intake gap closure. Driven by the post-mortem on CVE-2026-46333 (ssh-keysign-pwn) — disclosed 2026-05-14 by Qualys, missed by the toolkit at T+0 through T+3 because the existing source set (KEV, EPSS, NVD, RFC, PINS, GHSA, OSV) sits at the END of the disclosure pipeline. Adds primary-source polling, CVE-class alert surfacing, and seeds two retroactive catalog entries for the disclosures the toolkit should have caught.
|
package/bin/exceptd.js
CHANGED
|
@@ -1236,7 +1236,14 @@ function dispatchPlaybook(cmd, argv) {
|
|
|
1236
1236
|
// `--mode garbage` was silently accepted.
|
|
1237
1237
|
const VALID_MODES = ["self_service", "authorized_pentest", "ir_response", "ctf", "research", "compliance_audit"];
|
|
1238
1238
|
if (!VALID_MODES.includes(args.mode)) {
|
|
1239
|
-
|
|
1239
|
+
// v0.13.2: did-you-mean on flag-value typos (Levenshtein ≤ 2).
|
|
1240
|
+
const dym = suggestFlag(String(args.mode), VALID_MODES);
|
|
1241
|
+
const hint = dym ? ` Did you mean "${dym}"?` : '';
|
|
1242
|
+
return emitError(
|
|
1243
|
+
`run: --mode "${args.mode}" not in accepted set ${JSON.stringify(VALID_MODES)}.${hint}`,
|
|
1244
|
+
{ provided: args.mode, accepted: VALID_MODES, did_you_mean: dym ? [dym] : [] },
|
|
1245
|
+
pretty,
|
|
1246
|
+
);
|
|
1240
1247
|
}
|
|
1241
1248
|
runOpts.mode = args.mode;
|
|
1242
1249
|
}
|
|
@@ -2268,7 +2275,13 @@ function cmdBrief(runner, args, runOpts, pretty) {
|
|
|
2268
2275
|
if (onlyPhase != null) {
|
|
2269
2276
|
const ACCEPTED_PHASES = ["govern", "direct", "look"];
|
|
2270
2277
|
if (!ACCEPTED_PHASES.includes(onlyPhase)) {
|
|
2271
|
-
|
|
2278
|
+
const dym = suggestFlag(String(onlyPhase), ACCEPTED_PHASES);
|
|
2279
|
+
const hint = dym ? ` Did you mean "${dym}"?` : '';
|
|
2280
|
+
return emitError(
|
|
2281
|
+
`brief: --phase "${onlyPhase}" not in accepted set ${JSON.stringify(ACCEPTED_PHASES)}.${hint}`,
|
|
2282
|
+
{ verb: "brief", provided: onlyPhase, accepted: ACCEPTED_PHASES, did_you_mean: dym ? [dym] : [] },
|
|
2283
|
+
pretty,
|
|
2284
|
+
);
|
|
2272
2285
|
}
|
|
2273
2286
|
}
|
|
2274
2287
|
|
|
@@ -2998,7 +3011,13 @@ function cmdRun(runner, args, runOpts, pretty) {
|
|
|
2998
3011
|
const requested = Array.isArray(args.format) ? args.format[0] : args.format;
|
|
2999
3012
|
const VALID = ["summary", "markdown", "csaf-2.0", "csaf", "sarif", "openvex", "json"];
|
|
3000
3013
|
if (!VALID.includes(requested)) {
|
|
3001
|
-
|
|
3014
|
+
const dym = suggestFlag(String(requested), VALID);
|
|
3015
|
+
const hint = dym ? ` Did you mean "${dym}"?` : '';
|
|
3016
|
+
return emitError(
|
|
3017
|
+
`run: --format "${requested}" not in accepted set ${JSON.stringify(VALID)}.${hint}`,
|
|
3018
|
+
{ verb: "run", provided: requested, accepted: VALID, did_you_mean: dym ? [dym] : [] },
|
|
3019
|
+
pretty,
|
|
3020
|
+
);
|
|
3002
3021
|
}
|
|
3003
3022
|
if (requested === "summary") {
|
|
3004
3023
|
const cls = result.phases?.detect?.classification;
|
|
@@ -4788,7 +4807,13 @@ function cmdAttest(runner, args, runOpts, pretty) {
|
|
|
4788
4807
|
// accepting any value the operator passed.
|
|
4789
4808
|
const VALID_EXPORT_FORMATS = ["json", "csaf", "csaf-2.0"];
|
|
4790
4809
|
if (!VALID_EXPORT_FORMATS.includes(formatRaw)) {
|
|
4791
|
-
|
|
4810
|
+
const dym = suggestFlag(String(formatRaw), VALID_EXPORT_FORMATS);
|
|
4811
|
+
const hint = dym ? ` Did you mean "${dym}"?` : '';
|
|
4812
|
+
return emitError(
|
|
4813
|
+
`attest export: --format "${formatRaw}" not in accepted set ${JSON.stringify(VALID_EXPORT_FORMATS)}.${hint}`,
|
|
4814
|
+
{ verb: "attest export", provided: formatRaw, accepted: VALID_EXPORT_FORMATS, did_you_mean: dym ? [dym] : [] },
|
|
4815
|
+
pretty,
|
|
4816
|
+
);
|
|
4792
4817
|
}
|
|
4793
4818
|
const redacted = attestations.map(a => ({
|
|
4794
4819
|
session_id: a.session_id,
|
|
@@ -5180,16 +5205,24 @@ function cmdDoctor(runner, args, runOpts, pretty) {
|
|
|
5180
5205
|
|
|
5181
5206
|
// Selective subchecks. If any of the four flags is passed, run only those.
|
|
5182
5207
|
// If none are passed, run all four plus signing-status.
|
|
5208
|
+
// v0.13.3: --ai-config audits AI-assistant config-file permissions per
|
|
5209
|
+
// NEW-CTRL-050 (from the MAL-2026-SHAI-HULUD-OSS zeroday-lessons entry).
|
|
5210
|
+
// It's a separate flag because the check is opt-in — most operators
|
|
5211
|
+
// don't want their AI-config state probed by default.
|
|
5183
5212
|
const onlySigs = !!args.signatures;
|
|
5184
5213
|
const onlyCurrency = !!args.currency;
|
|
5185
5214
|
const onlyCves = !!args.cves;
|
|
5186
5215
|
const onlyRfcs = !!args.rfcs;
|
|
5187
|
-
const
|
|
5216
|
+
const onlyAiConfig = !!args["ai-config"];
|
|
5217
|
+
const anySelected = onlySigs || onlyCurrency || onlyCves || onlyRfcs || onlyAiConfig;
|
|
5188
5218
|
const runSigs = !anySelected || onlySigs;
|
|
5189
5219
|
const runCurrency = !anySelected || onlyCurrency;
|
|
5190
5220
|
const runCves = !anySelected || onlyCves;
|
|
5191
5221
|
const runRfcs = !anySelected || onlyRfcs;
|
|
5192
5222
|
const runSigning = !anySelected;
|
|
5223
|
+
// --ai-config is opt-in — never runs as part of the default no-flag
|
|
5224
|
+
// doctor pass. Operators ask for it explicitly.
|
|
5225
|
+
const runAiConfig = onlyAiConfig;
|
|
5193
5226
|
|
|
5194
5227
|
const checks = {};
|
|
5195
5228
|
const issues = [];
|
|
@@ -5428,6 +5461,102 @@ function cmdDoctor(runner, args, runOpts, pretty) {
|
|
|
5428
5461
|
}
|
|
5429
5462
|
}
|
|
5430
5463
|
|
|
5464
|
+
// v0.13.3 — AI-assistant config-file permission audit per NEW-CTRL-050
|
|
5465
|
+
// (from the MAL-2026-SHAI-HULUD-OSS zeroday-lessons entry). Walks
|
|
5466
|
+
// ~/.claude/, ~/.cursor/, ~/.codeium/, ~/.aider/, ~/.continue/ for
|
|
5467
|
+
// sensitive config files (settings.json, mcp.json, *.mcp_config.json,
|
|
5468
|
+
// api_key*, *.token, *.credentials) and reports any not at mode 0600.
|
|
5469
|
+
// The MAL-2026-SHAI-HULUD-OSS framework reads these files at
|
|
5470
|
+
// unprivileged-process scope; tightening to 0600 forces npm/node-spawned
|
|
5471
|
+
// processes that don't share UID to fail the read.
|
|
5472
|
+
//
|
|
5473
|
+
// Opt-in only — never runs as part of the default no-flag doctor pass.
|
|
5474
|
+
// Operators request it via `exceptd doctor --ai-config`.
|
|
5475
|
+
if (runAiConfig) {
|
|
5476
|
+
const os = require('os');
|
|
5477
|
+
const HOME = os.homedir();
|
|
5478
|
+
const AI_CONFIG_DIRS = [
|
|
5479
|
+
{ dir: '.claude', display: '~/.claude' },
|
|
5480
|
+
{ dir: '.cursor', display: '~/.cursor' },
|
|
5481
|
+
{ dir: '.codeium', display: '~/.codeium' },
|
|
5482
|
+
{ dir: '.aider', display: '~/.aider' },
|
|
5483
|
+
{ dir: '.continue', display: '~/.continue' },
|
|
5484
|
+
];
|
|
5485
|
+
// Files within those dirs that warrant the strict-mode check.
|
|
5486
|
+
const SENSITIVE_PATTERNS = [
|
|
5487
|
+
/^settings\.json$/,
|
|
5488
|
+
/^mcp\.json$/,
|
|
5489
|
+
/\.mcp_config\.json$/,
|
|
5490
|
+
/^api_key/,
|
|
5491
|
+
/\.token$/,
|
|
5492
|
+
/\.credentials$/,
|
|
5493
|
+
];
|
|
5494
|
+
const findings = [];
|
|
5495
|
+
let scannedDirs = 0;
|
|
5496
|
+
let scannedFiles = 0;
|
|
5497
|
+
function walk(absDir, displayRoot, rel) {
|
|
5498
|
+
if (!fs.existsSync(absDir)) return;
|
|
5499
|
+
let entries;
|
|
5500
|
+
try { entries = fs.readdirSync(absDir, { withFileTypes: true }); }
|
|
5501
|
+
catch { return; }
|
|
5502
|
+
for (const e of entries) {
|
|
5503
|
+
const childAbs = path.join(absDir, e.name);
|
|
5504
|
+
const childRel = rel ? rel + '/' + e.name : e.name;
|
|
5505
|
+
if (e.isDirectory()) {
|
|
5506
|
+
walk(childAbs, displayRoot, childRel);
|
|
5507
|
+
} else if (e.isFile()) {
|
|
5508
|
+
scannedFiles++;
|
|
5509
|
+
if (!SENSITIVE_PATTERNS.some((re) => re.test(e.name))) continue;
|
|
5510
|
+
let st;
|
|
5511
|
+
try { st = fs.statSync(childAbs); } catch { continue; }
|
|
5512
|
+
if (process.platform === 'win32') {
|
|
5513
|
+
// Windows POSIX mode bits don't carry meaningful ACL info.
|
|
5514
|
+
// Flag every sensitive file with a manual-review note rather
|
|
5515
|
+
// than emit a noisy permission claim that's likely wrong.
|
|
5516
|
+
findings.push({
|
|
5517
|
+
path: `${displayRoot}/${childRel}`,
|
|
5518
|
+
mode: null,
|
|
5519
|
+
severity: 'info',
|
|
5520
|
+
issue: 'win32_acl_check_not_implemented',
|
|
5521
|
+
hint: 'On Windows the POSIX mode bits are not load-bearing. Use icacls to confirm only the current user has read access. Tracked for v0.14+.',
|
|
5522
|
+
});
|
|
5523
|
+
continue;
|
|
5524
|
+
}
|
|
5525
|
+
const mode = st.mode & 0o777;
|
|
5526
|
+
if ((mode & 0o077) !== 0) {
|
|
5527
|
+
findings.push({
|
|
5528
|
+
path: `${displayRoot}/${childRel}`,
|
|
5529
|
+
mode: '0' + mode.toString(8),
|
|
5530
|
+
severity: 'warn',
|
|
5531
|
+
issue: 'group_or_other_readable',
|
|
5532
|
+
hint: `chmod 600 '${childAbs}' # NEW-CTRL-050: AI-assistant configs holding MCP tokens / API keys must be 0600 to defeat unprivileged exfil`,
|
|
5533
|
+
});
|
|
5534
|
+
}
|
|
5535
|
+
}
|
|
5536
|
+
}
|
|
5537
|
+
}
|
|
5538
|
+
for (const d of AI_CONFIG_DIRS) {
|
|
5539
|
+
const abs = path.join(HOME, d.dir);
|
|
5540
|
+
if (fs.existsSync(abs)) {
|
|
5541
|
+
scannedDirs++;
|
|
5542
|
+
walk(abs, d.display, '');
|
|
5543
|
+
}
|
|
5544
|
+
}
|
|
5545
|
+
const errorFindings = findings.filter((f) => f.severity === 'warn');
|
|
5546
|
+
checks.ai_config = {
|
|
5547
|
+
ok: errorFindings.length === 0,
|
|
5548
|
+
severity: errorFindings.length > 0 ? 'warn' : 'info',
|
|
5549
|
+
scanned_dirs: scannedDirs,
|
|
5550
|
+
scanned_files: scannedFiles,
|
|
5551
|
+
directories_inspected: AI_CONFIG_DIRS.map((d) => d.display),
|
|
5552
|
+
sensitive_patterns: ['settings.json', 'mcp.json', '*.mcp_config.json', 'api_key*', '*.token', '*.credentials'],
|
|
5553
|
+
findings,
|
|
5554
|
+
platform: process.platform,
|
|
5555
|
+
control_reference: 'NEW-CTRL-050 (MAL-2026-SHAI-HULUD-OSS lesson)',
|
|
5556
|
+
};
|
|
5557
|
+
if (errorFindings.length > 0) issues.push('ai_config');
|
|
5558
|
+
}
|
|
5559
|
+
|
|
5431
5560
|
// Walk every check and split: errors (severity error/missing/fail) vs warnings
|
|
5432
5561
|
// (severity warn). all_green is true ONLY when zero errors AND zero warnings.
|
|
5433
5562
|
const warnList = [];
|
|
@@ -6551,9 +6680,13 @@ function cmdCi(runner, args, runOpts, pretty) {
|
|
|
6551
6680
|
// Route through emitError so the body propagates exit codes via the
|
|
6552
6681
|
// emit() ok:false contract. ci-format-typo is operator-decision class
|
|
6553
6682
|
// (GENERIC_FAILURE), not DETECTED_ESCALATE.
|
|
6683
|
+
// v0.13.2: did-you-mean on the unknown format value (Levenshtein ≤ 2).
|
|
6684
|
+
const CI_FORMATS = ["summary", "markdown", "csaf-2.0", "sarif", "openvex", "json"];
|
|
6685
|
+
const dym = suggestFlag(String(fmt), CI_FORMATS);
|
|
6686
|
+
const hint = dym ? ` Did you mean "${dym}"?` : '';
|
|
6554
6687
|
emitError(
|
|
6555
|
-
`ci: --format "${fmt}" not in accepted set
|
|
6556
|
-
{ verb: "ci" },
|
|
6688
|
+
`ci: --format "${fmt}" not in accepted set ${JSON.stringify(CI_FORMATS)}.${hint}`,
|
|
6689
|
+
{ verb: "ci", provided: fmt, accepted: CI_FORMATS, did_you_mean: dym ? [dym] : [] },
|
|
6557
6690
|
pretty
|
|
6558
6691
|
);
|
|
6559
6692
|
return;
|
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-18T03:04:24.499Z",
|
|
4
4
|
"generator": "scripts/build-indexes.js",
|
|
5
5
|
"source_count": 54,
|
|
6
6
|
"source_hashes": {
|
|
7
|
-
"manifest.json": "
|
|
8
|
-
"data/atlas-ttps.json": "
|
|
9
|
-
"data/attack-techniques.json": "
|
|
10
|
-
"data/cve-catalog.json": "
|
|
11
|
-
"data/cwe-catalog.json": "
|
|
7
|
+
"manifest.json": "b1b4b86879805e28975155d7aa29c1d1463ec266f2c98a1045d543ecf5acaa6c",
|
|
8
|
+
"data/atlas-ttps.json": "2b021f47355365d1ba59078dfa582397c7a64c2b4ebea4657ea260a66b76daf6",
|
|
9
|
+
"data/attack-techniques.json": "76461dbec048c5e072435d57e3a04b780e3992dab9f316b1b52608e0a997e355",
|
|
10
|
+
"data/cve-catalog.json": "1d34601fbc4ff925ac38b8eb325375a32dc60ffaff31a23a5ca5f3e1524e88f8",
|
|
11
|
+
"data/cwe-catalog.json": "4a0036f9ec17af29e0df111ac77b94f8be6a52742bfd89ff3583096d23b75e35",
|
|
12
12
|
"data/d3fend-catalog.json": "a1fc2827ceb344669e148d55197dbf1b0e5b20bcc618e90517639c17d67ee82d",
|
|
13
13
|
"data/dlp-controls.json": "d2406c482dddd30e49203879999dc4b3a7fd4d0494d6a61d86b91ee76415df19",
|
|
14
14
|
"data/exploit-availability.json": "003a400f5ae5b15527589571679ccdb9b3a62e60073627b5fbdeb2a9fe330a7a",
|
|
15
|
-
"data/framework-control-gaps.json": "
|
|
15
|
+
"data/framework-control-gaps.json": "ce1535f13d29ab90fac99b983f38a23dd685702b3f12ac9f2371294cb9859ecf",
|
|
16
16
|
"data/global-frameworks.json": "9ba563a85f7f8d6c3c957de64945e20925a89d0ed6ea6fc561cf093811acf558",
|
|
17
17
|
"data/rfc-references.json": "e253a548c8a829d178d5aea601e268724b85c936ccbfa51c2e5d80c5f8efe2b0",
|
|
18
|
-
"data/zeroday-lessons.json": "
|
|
18
|
+
"data/zeroday-lessons.json": "1438620d2c8b0606eac4f63e620906b9ba079c57bfa7f737ceb6a50370cdc9a5",
|
|
19
19
|
"skills/kernel-lpe-triage/skill.md": "ae4a0af924d0078ffc6cd051a3ef9fce75a6a3f9c0c15d1c07900ae5faf80502",
|
|
20
20
|
"skills/ai-attack-surface/skill.md": "dcca7d92a1ab4d1e4c46356b614a138b1c1f79b65a6a290eccf2095d8d443993",
|
|
21
21
|
"skills/mcp-agent-trust/skill.md": "6821f6d38f6e23bbed953f8f86a279597b0b95a2d0548b5383e851bca7442531",
|
|
@@ -25,38 +25,38 @@
|
|
|
25
25
|
"skills/rag-pipeline-security/skill.md": "ff07e48918090247aef71def4150b0df372a24bcdaa34eb6e11d246b9e71e1ee",
|
|
26
26
|
"skills/ai-c2-detection/skill.md": "3da9f549f5c62e6163cddd70c8edccbef7be622d5a45fa89c90c6550e68c6b2e",
|
|
27
27
|
"skills/policy-exception-gen/skill.md": "a7d886f7fa99a150b040f158b09045ba45e107439315389aea785311b0013395",
|
|
28
|
-
"skills/threat-model-currency/skill.md": "
|
|
28
|
+
"skills/threat-model-currency/skill.md": "cf1cc27ae5ae68d336c56d9f3afd950641e1d8d5b9f90b64c2daf00abe92bab0",
|
|
29
29
|
"skills/global-grc/skill.md": "1dca534cce7612c1d26a7b1bfd088a811081555ecfa25b1f68cff2ca2ba28c98",
|
|
30
|
-
"skills/zeroday-gap-learn/skill.md": "
|
|
30
|
+
"skills/zeroday-gap-learn/skill.md": "e26f194880cd6acf46abe31e9348d445e9222c7691e9b9b953662c4a472462f5",
|
|
31
31
|
"skills/pqc-first/skill.md": "a7131b65d0ceee47887b16679ee4e4b065d32d8751fe59921762388703662913",
|
|
32
|
-
"skills/skill-update-loop/skill.md": "
|
|
32
|
+
"skills/skill-update-loop/skill.md": "b6f3bee321833dc18f5624a9be4d28673d22e22018254b0bd1f3690b945073af",
|
|
33
33
|
"skills/security-maturity-tiers/skill.md": "ed962937c45f3d95f325f231b787d272fe45c4cb91d4c5a2d982493d722c2acf",
|
|
34
|
-
"skills/researcher/skill.md": "
|
|
34
|
+
"skills/researcher/skill.md": "fd441131484dc5af4cd785ded0bac039123e6205483543752cb16fa508460c00",
|
|
35
35
|
"skills/attack-surface-pentest/skill.md": "0d301beb9fb8e247ec80256a7e647804b5f9a41c7156e5724555ca9f93ccb986",
|
|
36
|
-
"skills/fuzz-testing-strategy/skill.md": "
|
|
36
|
+
"skills/fuzz-testing-strategy/skill.md": "fb8c261def9e3344b44fd219c209027029e1eddf0e6bee1ecffb2d2176e1585e",
|
|
37
37
|
"skills/dlp-gap-analysis/skill.md": "1c4e1d7da2421b82f202eaf2c9e21876af34ab5c76ce1359166842ee473f02dd",
|
|
38
38
|
"skills/supply-chain-integrity/skill.md": "ad69b72f5c5df095f8618b977fbc8f0fbff396eebd4a8448b44c3f93309f63f9",
|
|
39
|
-
"skills/defensive-countermeasure-mapping/skill.md": "
|
|
39
|
+
"skills/defensive-countermeasure-mapping/skill.md": "3d0c7ca85f32ee1fe74598889361ef2be16d099fe6e9e8d8c8184b7004306b30",
|
|
40
40
|
"skills/identity-assurance/skill.md": "4ee7096fd82997c66b0f9e825ea3c04c3aa84768b74e6f668c1a9104104138cf",
|
|
41
|
-
"skills/ot-ics-security/skill.md": "
|
|
41
|
+
"skills/ot-ics-security/skill.md": "7423cca19aab1026c07de63279137441018345731d3ee895c474316d432adaa2",
|
|
42
42
|
"skills/coordinated-vuln-disclosure/skill.md": "0e875953bb8a38a89c8ec5d2a9ef967b12e9a9f166dc9356723f10304fd0535e",
|
|
43
|
-
"skills/threat-modeling-methodology/skill.md": "
|
|
44
|
-
"skills/webapp-security/skill.md": "
|
|
45
|
-
"skills/ai-risk-management/skill.md": "
|
|
43
|
+
"skills/threat-modeling-methodology/skill.md": "cebeba3940320ebc5b44ad2bb7b4cdcda412257c1a6319a1b7379c875ebe8d6a",
|
|
44
|
+
"skills/webapp-security/skill.md": "f2063eaea3f5ddf0f3d37b41985bf522b682a41f104796b3f0dff611cefd043c",
|
|
45
|
+
"skills/ai-risk-management/skill.md": "2b611eb8fa4841fdfc3f1dd1ffd504a46c6ecdc654213a955efbabefb6b1db87",
|
|
46
46
|
"skills/sector-healthcare/skill.md": "a18e11d25524cdbf40df3798f4c2aa3cb51a4db1b088242ea53fa2885e86b64c",
|
|
47
47
|
"skills/sector-financial/skill.md": "023b5440d614e6b83ba7294219bcac3cdbffd28fdfdd5f0ec23abbeea71b8230",
|
|
48
|
-
"skills/sector-federal-government/skill.md": "
|
|
49
|
-
"skills/sector-energy/skill.md": "
|
|
50
|
-
"skills/sector-telecom/skill.md": "
|
|
51
|
-
"skills/api-security/skill.md": "
|
|
48
|
+
"skills/sector-federal-government/skill.md": "a73c3f36f23c12750d369931b7e3f884edae4a8aef35fc8690d15ef4500c4dd0",
|
|
49
|
+
"skills/sector-energy/skill.md": "91f00e7a9be2608393ec8cb6d5f0c9828f81b954a12a7c9fd04bd642b9091e09",
|
|
50
|
+
"skills/sector-telecom/skill.md": "59193e39c2fd73fdd7fede38a956bc730bbe4b712d7d6020788bb4d85f001ad8",
|
|
51
|
+
"skills/api-security/skill.md": "9fc2252cbcf6162591e70d0bf5499a430b0584495ad584ce49fb7daf070d335f",
|
|
52
52
|
"skills/cloud-security/skill.md": "c9fad9ed3663cf2faec74ad8f06d62eb86e6636f79933560d8c8d50e0e82d1da",
|
|
53
53
|
"skills/container-runtime-security/skill.md": "605a8e8eb1af09835b967ec7179456015ec116c6b9051af3a8d225866cc2f7af",
|
|
54
|
-
"skills/mlops-security/skill.md": "
|
|
54
|
+
"skills/mlops-security/skill.md": "72429f05010accbcb191cb1544f1b88493c2f5249362846e5713ec3226b83dc2",
|
|
55
55
|
"skills/incident-response-playbook/skill.md": "2017515d899c1b2bcb878bc6731e4059623ac52345b2cebbd92204583657bf60",
|
|
56
56
|
"skills/ransomware-response/skill.md": "2e4fc488f86ed1ba7791ab0e7021160d8ca5ad33a02cdf92a5b916c8afecaa54",
|
|
57
|
-
"skills/email-security-anti-phishing/skill.md": "
|
|
58
|
-
"skills/age-gates-child-safety/skill.md": "
|
|
59
|
-
"skills/cloud-iam-incident/skill.md": "
|
|
57
|
+
"skills/email-security-anti-phishing/skill.md": "250f266908f51f99a4cb3aec0d5dacfcf91fac9f3d95e5a117429a40ed2ff45a",
|
|
58
|
+
"skills/age-gates-child-safety/skill.md": "51295c849bcced965b6448eb6b4bbd5caef5ba0b0cea7ce48abbacf47d331621",
|
|
59
|
+
"skills/cloud-iam-incident/skill.md": "5ec3800a0049b2123aff67bfab4ff28491a86d2daeb712283e5e88b10c3d5d7b",
|
|
60
60
|
"skills/idp-incident-response/skill.md": "e67a2576e7f1c3bf89f499f5c977bc470ef29e8b3e3e45f4cb5bd45a82674282"
|
|
61
61
|
},
|
|
62
62
|
"skill_count": 42,
|
|
@@ -72,13 +72,13 @@
|
|
|
72
72
|
"dlp_refs": 0
|
|
73
73
|
},
|
|
74
74
|
"trigger_table_entries": 538,
|
|
75
|
-
"chains_cve_entries":
|
|
75
|
+
"chains_cve_entries": 35,
|
|
76
76
|
"chains_cwe_entries": 55,
|
|
77
77
|
"jurisdictions_indexed": 29,
|
|
78
78
|
"handoff_dag_nodes": 42,
|
|
79
79
|
"summary_cards": 42,
|
|
80
80
|
"section_offsets_skills": 42,
|
|
81
|
-
"token_budget_total_approx":
|
|
81
|
+
"token_budget_total_approx": 404483,
|
|
82
82
|
"recipes": 8,
|
|
83
83
|
"jurisdiction_clocks": 29,
|
|
84
84
|
"did_ladders": 8,
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"artifact": "data/framework-control-gaps.json",
|
|
64
64
|
"path": "data/framework-control-gaps.json",
|
|
65
65
|
"schema_version": "1.0.0",
|
|
66
|
-
"entry_count":
|
|
66
|
+
"entry_count": 142
|
|
67
67
|
},
|
|
68
68
|
{
|
|
69
69
|
"date": "2026-05-15",
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"artifact": "data/zeroday-lessons.json",
|
|
88
88
|
"path": "data/zeroday-lessons.json",
|
|
89
89
|
"schema_version": "1.1.0",
|
|
90
|
-
"entry_count":
|
|
90
|
+
"entry_count": 39
|
|
91
91
|
},
|
|
92
92
|
{
|
|
93
93
|
"date": "2026-05-15",
|
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
"artifact": "data/cve-catalog.json",
|
|
103
103
|
"path": "data/cve-catalog.json",
|
|
104
104
|
"schema_version": "1.0.0",
|
|
105
|
-
"entry_count":
|
|
105
|
+
"entry_count": 40
|
|
106
106
|
},
|
|
107
107
|
{
|
|
108
108
|
"date": "2026-05-13",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"rebuild_after_days": 365,
|
|
63
63
|
"note": "Per-entry last_verified governs decay. Skills depending on this catalog must check entry freshness before high-stakes use."
|
|
64
64
|
},
|
|
65
|
-
"entry_count":
|
|
65
|
+
"entry_count": 40,
|
|
66
66
|
"sample_keys": [
|
|
67
67
|
"CVE-2025-53773",
|
|
68
68
|
"CVE-2026-30615",
|
|
@@ -172,7 +172,7 @@
|
|
|
172
172
|
"rebuild_after_days": 365,
|
|
173
173
|
"note": "Per-entry last_verified governs decay. Skills depending on this catalog must check entry freshness before high-stakes use."
|
|
174
174
|
},
|
|
175
|
-
"entry_count":
|
|
175
|
+
"entry_count": 142,
|
|
176
176
|
"sample_keys": [
|
|
177
177
|
"ALL-AI-PIPELINE-INTEGRITY",
|
|
178
178
|
"ALL-MCP-TOOL-TRUST",
|
|
@@ -238,7 +238,7 @@
|
|
|
238
238
|
"rebuild_after_days": 365,
|
|
239
239
|
"note": "Per-entry last_verified governs decay. Skills depending on this catalog must check entry freshness before high-stakes use."
|
|
240
240
|
},
|
|
241
|
-
"entry_count":
|
|
241
|
+
"entry_count": 39,
|
|
242
242
|
"sample_keys": [
|
|
243
243
|
"CVE-2026-31431",
|
|
244
244
|
"CVE-2025-53773",
|