@blamejs/exceptd-skills 0.13.47 → 0.13.49
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 +30 -0
- package/bin/exceptd.js +100 -25
- package/data/_indexes/_meta.json +2 -2
- package/lib/collectors/cred-stores.js +18 -0
- package/lib/collectors/crypto-codebase.js +3 -0
- package/lib/collectors/library-author.js +24 -3
- package/lib/collectors/secrets.js +47 -1
- package/manifest.json +44 -44
- package/package.json +1 -1
- package/sbom.cdx.json +22 -22
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.13.49 — 2026-05-21
|
|
4
|
+
|
|
5
|
+
`discover` covers four previously-invisible collectors. CLI UX cleanup across welcome banner, help text, attestation warning.
|
|
6
|
+
|
|
7
|
+
### Bugs
|
|
8
|
+
|
|
9
|
+
- **`discover` recommends `cicd-pipeline-compromise`, `mcp`, `ai-api`, and `crypto`.** Before, the cwd-aware recommender only knew about 9 of the 13 collectors — `discover` from a repo with `.github/workflows/` never surfaced the CI/CD posture playbook; `mcp` / `ai-api` were invisible even when the operator had MCP client config or shell rc files in their home; `crypto` was absent from the Linux branch alongside `hardening` / `runtime`. New probes: `.github/workflows/*.yml` for CI/CD, `~/.cursor/mcp.json` + `~/.config/claude` + `~/.codeium/windsurf/mcp_config.json` + `~/.gemini/settings.json` for MCP clients, `~/.bashrc` + `~/.zshrc` + `~/.profile` for shell rc, plus `crypto` always on Linux.
|
|
10
|
+
- **`discover` reason text drops the misleading "node lockfile" claim.** A `package.json`-only repo (no `package-lock.json`) used to receive the recommendation reason "git repo + node lockfile" even though the lockfile didn't exist. The reason now says "node project" (and similarly "python project" / "rust project" / "go project"), which is accurate for the broad manifest-OR-lockfile trigger.
|
|
11
|
+
- **`exceptd run --scope code` next-step suggestion is omitted from `discover` when no code-scope playbooks were recommended.** Previously, discover from an empty cwd suggested `exceptd run --scope code` even though no code playbooks applied — operators following the suggestion got every code-scope playbook running against an empty tree and a multi-hundred-KB JSON dump. Now the next-steps list shows `--scope code` only when at least one code-scope recommendation fired.
|
|
12
|
+
- **`exceptd help` section header drops the stale `v0.12.0 canonical surface` pin.** The surface evolves with each release; the header now reads `Canonical verbs` without a frozen version label.
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
|
|
16
|
+
- **Welcome banner enumerates the playbook starting set by trigger rather than by abstract category** (`git repos:`, `GitHub Actions:`, `Linux hosts:`, `AI assistants:`, `containers:`). Each row names the artifact that triggers the recommendation, and the banner explicitly points at `exceptd discover` as the authoritative recommender.
|
|
17
|
+
- **Attestation unsigned warning shrinks to a single line on consumer installs.** Previously every `exceptd run` from a globally-installed package (e.g. `npm install -g`) emitted a 4-line warning prescribing `exceptd doctor --fix` — but consumer installs land the package under `node_modules/` where `.keys/` typically isn't writable by the operator. The collector now detects consumer-install layout (PKG_ROOT under `node_modules/` OR parent dir is `@blamejs`) and prints `[attest] writing unsigned attestation (consumer install — signing is contributor-only).` instead. Contributor checkouts still see the full nudge.
|
|
18
|
+
|
|
19
|
+
## 0.13.48 — 2026-05-21
|
|
20
|
+
|
|
21
|
+
Collector predicate tightening across `secrets`, `library-author`, `crypto-codebase`, and `cred-stores`.
|
|
22
|
+
|
|
23
|
+
### Bugs
|
|
24
|
+
|
|
25
|
+
- **`secrets` collector demotes hits scoped exclusively to test / fixture / example paths.** Previously a JWT literal in `fulcio_test.go` or a private-key block in `cosign-test.key` flipped `jwt-token-with-secret-context` / `ssh-private-key-block` to `hit`. The collector now splits hits into production-scope vs. test-scope (segments `/test/` `/tests/` `/spec/` `/fixtures/` `/examples/` `/samples/` `/demo/` `/testdata/`, plus `*.test.<ext>` / `*.spec.<ext>` / `*_test.<ext>` / `*-test[-.]*` filename conventions). The indicator fires only when at least one production-scope hit exists. Test-only hits stay visible in the `secret-regex-scan-text-files` artifact for operator inspection but don't trip the signal. Mirrors the existing `crypto-codebase` demotion pattern.
|
|
26
|
+
- **`library-author` recognises container-native publish workflows.** The previous heuristic only matched npm / pypi / cargo / goreleaser / softprops-action-gh-release publish paths. Workflows using `ko publish` / `cosign sign(-blob)` / `crane push` / `oras push` / `docker push` / `docker/build-push-action` were missed, which falsely flipped `publish-workflow-no-id-token-write` on projects (e.g. sigstore/cosign) that use `id-token: write` for OIDC-based publishing. Now those workflows are recognized as publish-related, AND any workflow declaring `id-token: write` inside a `permissions:` block with executable `steps:` is treated as publish context.
|
|
27
|
+
- **`crypto-codebase` test-path demotion now covers Go's `_test.go` convention.** The previous regex matched only `*.test.<ext>` / `*.spec.<ext>` (dot-separated). Go convention is `foo_test.go` (underscore-separated); those test files were not demoted and false-positive'd indicators like `weak-hash-import` (md5 in a Go test using a "token" variable). Added `(?:^|[\\/])[^\\/]+_test\.[a-z]+$` to the demotion regex.
|
|
28
|
+
|
|
29
|
+
### Features
|
|
30
|
+
|
|
31
|
+
- **`cred-stores` surfaces a `credentials-file-perms-check` artifact** documenting whether the POSIX-mode-bit check ran (`captured: true` on Linux / macOS) or was skipped (`captured: false, reason: "...skipped on win32..."` on Windows). Previously the `credentials-file-bad-perms` signal was silently absent from `signal_overrides` on Windows, indistinguishable from "indicator not catalogued". Mirrors the `secrets` collector's `world-writable-secret-files` skip pattern.
|
|
32
|
+
|
|
3
33
|
## 0.13.47 — 2026-05-21
|
|
4
34
|
|
|
5
35
|
`cicd-pipeline-compromise` collect | run pipe now produces a verdict when the operator opts in to the CI-fleet ownership attestation.
|
package/bin/exceptd.js
CHANGED
|
@@ -334,9 +334,14 @@ If you know what you want:
|
|
|
334
334
|
exceptd ci --scope code # CI gate against every code-scoped playbook
|
|
335
335
|
|
|
336
336
|
Common starting playbooks
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
337
|
+
git repos: secrets, sbom, library-author, crypto-codebase
|
|
338
|
+
GitHub Actions: cicd-pipeline-compromise (.github/workflows/ present)
|
|
339
|
+
Linux hosts: kernel, hardening, runtime, cred-stores, crypto
|
|
340
|
+
AI assistants: mcp (MCP client config), ai-api (shell rc + AI key exports)
|
|
341
|
+
containers: containers (Dockerfile / docker-compose)
|
|
342
|
+
|
|
343
|
+
\`exceptd discover\` is the authoritative recommender — it inspects your
|
|
344
|
+
cwd + host and only suggests the playbooks that actually apply.
|
|
340
345
|
|
|
341
346
|
Full reference: exceptd help
|
|
342
347
|
Per-verb help: exceptd <verb> --help
|
|
@@ -349,8 +354,8 @@ function printHelp() {
|
|
|
349
354
|
Usage: exceptd <command> [args]
|
|
350
355
|
npx @blamejs/exceptd-skills <command> [args]
|
|
351
356
|
|
|
352
|
-
|
|
353
|
-
|
|
357
|
+
Canonical verbs
|
|
358
|
+
───────────────
|
|
354
359
|
|
|
355
360
|
brief [playbook] Unified info doc — jurisdictions + threat context
|
|
356
361
|
+ preconditions + artifacts + indicators. Replaces
|
|
@@ -4275,18 +4280,28 @@ function maybeSignAttestation(filePath) {
|
|
|
4275
4280
|
// Operators who set `.keys/private.pem` get tamper-evident attestations;
|
|
4276
4281
|
// operators without the keypair get a single nudge per session telling them
|
|
4277
4282
|
// exactly how to enable signing.
|
|
4283
|
+
//
|
|
4284
|
+
// Consumer installs (`npm install -g`) land PKG_ROOT under
|
|
4285
|
+
// node_modules/ where the operator typically can't write to
|
|
4286
|
+
// .keys/. For those installs the multi-line nudge prescribes a
|
|
4287
|
+
// remediation (doctor --fix) the operator doesn't own — surface a
|
|
4288
|
+
// single-line marker so the unsigned attestation isn't silent, but
|
|
4289
|
+
// skip the call-to-action that doesn't apply.
|
|
4278
4290
|
if (!fs.existsSync(privKeyPath) && !process.env.EXCEPTD_UNSIGNED_WARNED) {
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4291
|
+
const pkgRootSegments = PKG_ROOT.split(/[\\/]/);
|
|
4292
|
+
const isConsumerInstall =
|
|
4293
|
+
pkgRootSegments.includes("node_modules") ||
|
|
4294
|
+
path.basename(path.dirname(PKG_ROOT)) === "@blamejs";
|
|
4295
|
+
if (isConsumerInstall) {
|
|
4296
|
+
process.stderr.write("[attest] writing unsigned attestation (consumer install — signing is contributor-only).\n");
|
|
4297
|
+
} else {
|
|
4298
|
+
process.stderr.write(
|
|
4299
|
+
"[attest] attestation will be written UNSIGNED (no private key at .keys/private.pem). " +
|
|
4300
|
+
"Operators reading the attestation later can verify the SHA-256 hash but not authenticity. " +
|
|
4301
|
+
"Enable Ed25519 signing: `exceptd doctor --fix` (or for contributor checkouts: `node $(exceptd path)/lib/sign.js generate-keypair`). " +
|
|
4302
|
+
"Suppress this notice: export EXCEPTD_UNSIGNED_WARNED=1.\n"
|
|
4303
|
+
);
|
|
4304
|
+
}
|
|
4290
4305
|
process.env.EXCEPTD_UNSIGNED_WARNED = "1";
|
|
4291
4306
|
}
|
|
4292
4307
|
try {
|
|
@@ -5535,17 +5550,60 @@ function cmdDiscover(runner, args, runOpts, pretty) {
|
|
|
5535
5550
|
// Build recommendation set. Dedup by playbook id so multi-trigger rules
|
|
5536
5551
|
// don't double-list.
|
|
5537
5552
|
const isRepo = detected.includes(".git/");
|
|
5538
|
-
const
|
|
5553
|
+
const hasNodeManifest = detected.includes("package.json");
|
|
5554
|
+
const hasNodeLockfile = detected.includes("package-lock.json")
|
|
5539
5555
|
|| detected.includes("yarn.lock") || detected.includes("pnpm-lock.yaml");
|
|
5556
|
+
const hasNode = hasNodeManifest || hasNodeLockfile;
|
|
5540
5557
|
const hasPython = detected.includes("pyproject.toml") || detected.includes("requirements.txt")
|
|
5541
5558
|
|| detected.includes("Pipfile");
|
|
5542
5559
|
const hasRust = detected.includes("Cargo.toml");
|
|
5543
5560
|
const hasGo = detected.includes("go.mod");
|
|
5544
|
-
const
|
|
5561
|
+
const hasProject = hasNode || hasPython || hasRust || hasGo;
|
|
5545
5562
|
const hasContainers = detected.includes("Dockerfile") || detected.includes("docker-compose.yml")
|
|
5546
5563
|
|| detected.includes("docker-compose.yaml");
|
|
5547
5564
|
const isLinux = hostPlatform === "linux";
|
|
5548
5565
|
|
|
5566
|
+
// .github/workflows/ directory probe — surfaces the CI/CD posture
|
|
5567
|
+
// playbook when present.
|
|
5568
|
+
let hasGithubWorkflows = false;
|
|
5569
|
+
try {
|
|
5570
|
+
const wfDir = path.join(cwd, ".github", "workflows");
|
|
5571
|
+
if (fs.existsSync(wfDir) && fs.statSync(wfDir).isDirectory()) {
|
|
5572
|
+
const entries = fs.readdirSync(wfDir).filter(f => /\.(ya?ml)$/i.test(f));
|
|
5573
|
+
if (entries.length > 0) hasGithubWorkflows = true;
|
|
5574
|
+
}
|
|
5575
|
+
} catch { /* swallow */ }
|
|
5576
|
+
|
|
5577
|
+
// Home-resident MCP client config probe — surfaces the `mcp`
|
|
5578
|
+
// playbook when at least one supported client is configured on
|
|
5579
|
+
// this host. Best-effort: silently skip if home isn't readable.
|
|
5580
|
+
let hasMcpClientConfig = false;
|
|
5581
|
+
const homeForProbe = process.env.HOME || process.env.USERPROFILE || null;
|
|
5582
|
+
if (homeForProbe) {
|
|
5583
|
+
const mcpProbes = [
|
|
5584
|
+
path.join(homeForProbe, ".cursor", "mcp.json"),
|
|
5585
|
+
path.join(homeForProbe, ".config", "claude"),
|
|
5586
|
+
path.join(homeForProbe, ".claude"),
|
|
5587
|
+
path.join(homeForProbe, ".codeium", "windsurf", "mcp_config.json"),
|
|
5588
|
+
path.join(homeForProbe, ".gemini", "settings.json"),
|
|
5589
|
+
];
|
|
5590
|
+
for (const p of mcpProbes) {
|
|
5591
|
+
try { if (fs.existsSync(p)) { hasMcpClientConfig = true; break; } } catch { /* swallow */ }
|
|
5592
|
+
}
|
|
5593
|
+
}
|
|
5594
|
+
|
|
5595
|
+
// Shell rc presence — proxy signal for "user has a shell-driven
|
|
5596
|
+
// workflow that might export AI API keys". The ai-api collector
|
|
5597
|
+
// checks rc files + vendor dotfiles regardless; surface the
|
|
5598
|
+
// recommendation when at least one rc file exists.
|
|
5599
|
+
let hasShellRc = false;
|
|
5600
|
+
if (homeForProbe) {
|
|
5601
|
+
const rcProbes = [".bashrc", ".bash_profile", ".zshrc", ".zprofile", ".profile"];
|
|
5602
|
+
for (const f of rcProbes) {
|
|
5603
|
+
try { if (fs.existsSync(path.join(homeForProbe, f))) { hasShellRc = true; break; } } catch { /* swallow */ }
|
|
5604
|
+
}
|
|
5605
|
+
}
|
|
5606
|
+
|
|
5549
5607
|
const recs = [];
|
|
5550
5608
|
const seen = new Set();
|
|
5551
5609
|
function recommend(id, reason) {
|
|
@@ -5554,22 +5612,32 @@ function cmdDiscover(runner, args, runOpts, pretty) {
|
|
|
5554
5612
|
recs.push({ id, reason });
|
|
5555
5613
|
}
|
|
5556
5614
|
|
|
5557
|
-
if (isRepo &&
|
|
5615
|
+
if (isRepo && hasProject) {
|
|
5558
5616
|
const langs = [hasNode && "node", hasPython && "python", hasRust && "rust", hasGo && "go"]
|
|
5559
5617
|
.filter(Boolean).join("/");
|
|
5560
|
-
recommend("secrets", `git repo + ${langs}
|
|
5561
|
-
recommend("sbom", `git repo + ${langs}
|
|
5562
|
-
recommend("library-author", `git repo + ${langs}
|
|
5563
|
-
recommend("crypto-codebase", `git repo + ${langs}
|
|
5618
|
+
recommend("secrets", `git repo + ${langs} project → check for committed credentials`);
|
|
5619
|
+
recommend("sbom", `git repo + ${langs} project → SBOM + supply-chain integrity`);
|
|
5620
|
+
recommend("library-author", `git repo + ${langs} project → publisher-side audit`);
|
|
5621
|
+
recommend("crypto-codebase", `git repo + ${langs} project → cryptographic primitive review`);
|
|
5564
5622
|
}
|
|
5565
5623
|
if (hasContainers) {
|
|
5566
5624
|
recommend("containers", "Dockerfile / docker-compose present → container security review");
|
|
5567
5625
|
}
|
|
5626
|
+
if (hasGithubWorkflows) {
|
|
5627
|
+
recommend("cicd-pipeline-compromise", ".github/workflows/ present → CI/CD posture (fork-PR / OIDC / floating-tag)");
|
|
5628
|
+
}
|
|
5629
|
+
if (hasMcpClientConfig) {
|
|
5630
|
+
recommend("mcp", "MCP client config present in home → MCP supply-chain audit");
|
|
5631
|
+
}
|
|
5632
|
+
if (hasShellRc) {
|
|
5633
|
+
recommend("ai-api", "shell rc present in home → AI API key + cred-carrier audit");
|
|
5634
|
+
}
|
|
5568
5635
|
if (isLinux) {
|
|
5569
5636
|
recommend("kernel", "Linux host detected → kernel LPE / privilege escalation triage");
|
|
5570
5637
|
recommend("hardening", "Linux host detected → system hardening review");
|
|
5571
5638
|
recommend("runtime", "Linux host detected → runtime behavior review");
|
|
5572
5639
|
recommend("cred-stores", "Linux host detected → credential store review");
|
|
5640
|
+
recommend("crypto", "Linux host detected → host crypto posture (OpenSSL / sshd PQC readiness)");
|
|
5573
5641
|
}
|
|
5574
5642
|
// Always include cross-cutting framework correlation.
|
|
5575
5643
|
recommend("framework", "cross-cutting: framework correlation always applicable");
|
|
@@ -5587,12 +5655,19 @@ function cmdDiscover(runner, args, runOpts, pretty) {
|
|
|
5587
5655
|
rec.collect_cmd = hasCollector ? `exceptd collect ${rec.id}` : null;
|
|
5588
5656
|
}
|
|
5589
5657
|
|
|
5658
|
+
// Next-step suggestions are conditional on what discover detected.
|
|
5659
|
+
// From an empty / no-code-detected cwd, suggesting `run --scope code`
|
|
5660
|
+
// would silently run every code-scope playbook against an empty tree
|
|
5661
|
+
// and produce a multi-hundred-KB JSON dump for no useful reason.
|
|
5662
|
+
const recHasCodeScope = recs.some(r => ["secrets", "sbom", "library-author", "crypto-codebase", "containers", "cicd-pipeline-compromise"].includes(r.id));
|
|
5590
5663
|
const nextSteps = [
|
|
5591
5664
|
"exceptd brief <playbook> # learn what a playbook checks",
|
|
5592
5665
|
"exceptd run <playbook> # run it",
|
|
5593
|
-
"exceptd run --scope code # run all code-scoped playbooks (auto-detected)",
|
|
5594
|
-
"exceptd ci --scope code # CI-gate against all code-scoped playbooks",
|
|
5595
5666
|
];
|
|
5667
|
+
if (recHasCodeScope) {
|
|
5668
|
+
nextSteps.push("exceptd run --scope code # run all code-scoped playbooks (those applicable to this cwd)");
|
|
5669
|
+
nextSteps.push("exceptd ci --scope code # CI-gate against all code-scoped playbooks");
|
|
5670
|
+
}
|
|
5596
5671
|
|
|
5597
5672
|
const out = {
|
|
5598
5673
|
verb: "discover",
|
package/data/_indexes/_meta.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema_version": "1.1.0",
|
|
3
|
-
"generated_at": "2026-05-
|
|
3
|
+
"generated_at": "2026-05-21T17:42:36.651Z",
|
|
4
4
|
"generator": "scripts/build-indexes.js",
|
|
5
5
|
"source_count": 54,
|
|
6
6
|
"source_hashes": {
|
|
7
|
-
"manifest.json": "
|
|
7
|
+
"manifest.json": "188c660ebfd03913aafe0a2d8fc7975081b6a1c786eb0201338e62985b2f51c7",
|
|
8
8
|
"data/atlas-ttps.json": "d296c1d3e71807c9279b731f047e57796e85137f186586743a8cdad214b408f9",
|
|
9
9
|
"data/attack-techniques.json": "49b6010b317edd219def135171ea8f3b1bbf1e00e9c5a08bf7237215ff54e2c3",
|
|
10
10
|
"data/cve-catalog.json": "a09c83af3f9679a7ea73935726a1ff9de2cab94b4ab6321fc017fc147747d7c3",
|
|
@@ -439,6 +439,24 @@ function collect({ cwd = process.cwd(), env = process.env, args = {} } = {}) {
|
|
|
439
439
|
captured: false,
|
|
440
440
|
reason: "secret-tool / security dump-keychain require interactive auth or platform-specific binaries; out of stdlib collector scope",
|
|
441
441
|
},
|
|
442
|
+
// Surface the POSIX-mode-bit skip on Windows so operators see the
|
|
443
|
+
// indicator was considered but skipped, mirroring the secrets
|
|
444
|
+
// collector's world-writable-secret-files skip artifact. Without
|
|
445
|
+
// this, credentials-file-bad-perms silently absent from
|
|
446
|
+
// signal_overrides looks indistinguishable from "indicator not
|
|
447
|
+
// catalogued".
|
|
448
|
+
"credentials-file-perms-check": isPosix
|
|
449
|
+
? {
|
|
450
|
+
value: permViolations.length > 0
|
|
451
|
+
? `${permViolations.length} carrier(s) with mode != expected: ${permViolations.map(v => `${v.id}=${v.mode_octal}`).join(", ")}`
|
|
452
|
+
: "all checked carriers at expected mode",
|
|
453
|
+
captured: true,
|
|
454
|
+
}
|
|
455
|
+
: {
|
|
456
|
+
value: "skipped on win32 — POSIX mode bits not load-bearing",
|
|
457
|
+
captured: false,
|
|
458
|
+
reason: "Windows uses ACLs, not POSIX mode bits; credentials-file-bad-perms indicator left to operator-supplied evidence on this platform",
|
|
459
|
+
},
|
|
442
460
|
};
|
|
443
461
|
|
|
444
462
|
if (permViolations.length > 0) {
|
|
@@ -59,7 +59,10 @@ function isTestPath(rel) {
|
|
|
59
59
|
for (const seg of TEST_PATH_SEGMENTS) {
|
|
60
60
|
if (norm.includes(seg)) return true;
|
|
61
61
|
}
|
|
62
|
+
// `foo.test.js`, `bar.spec.py` (dot-separated)
|
|
62
63
|
if (/\.(test|spec)\.[a-z]+$/i.test(rel)) return true;
|
|
64
|
+
// `foo_test.go` (Go convention), `_test.py` (some Python projects)
|
|
65
|
+
if (/(?:^|[\\/])[^\\/]+_test\.[a-z]+$/i.test(rel)) return true;
|
|
63
66
|
return false;
|
|
64
67
|
}
|
|
65
68
|
|
|
@@ -66,9 +66,17 @@ function walkWorkflows(root) {
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
function looksLikePublishWorkflow(name, content) {
|
|
69
|
-
// Heuristic: filename starts with `release`/`publish`/`deploy
|
|
70
|
-
// the workflow body
|
|
71
|
-
//
|
|
69
|
+
// Heuristic: filename starts with `release`/`publish`/`deploy`, OR
|
|
70
|
+
// the workflow body invokes a known publish/release tool (npm /
|
|
71
|
+
// pypi / cargo / goreleaser / ko / cosign / crane / oras / docker /
|
|
72
|
+
// GitHub releases / sigstore-action). The container-native shapes
|
|
73
|
+
// matter because projects that publish via `ko publish` / `cosign
|
|
74
|
+
// sign-blob` (sigstore-style) DO use `id-token: write`, and the
|
|
75
|
+
// narrower npm/pypi/cargo matcher missed those workflows entirely.
|
|
76
|
+
// Filename `build.*` deliberately omitted — many projects use it
|
|
77
|
+
// for ordinary CI (lint / test / typecheck), not publishing.
|
|
78
|
+
// Cosign-style `build.yaml` is still recognized via its body
|
|
79
|
+
// content (cosign / id-token: write / etc.).
|
|
72
80
|
const lower = name.toLowerCase();
|
|
73
81
|
if (/^(release|publish|deploy)/.test(lower)) return true;
|
|
74
82
|
if (/\bnpm\s+publish\b/.test(content)) return true;
|
|
@@ -76,6 +84,19 @@ function looksLikePublishWorkflow(name, content) {
|
|
|
76
84
|
if (/\bcargo\s+publish\b/.test(content)) return true;
|
|
77
85
|
if (/goreleaser/.test(content)) return true;
|
|
78
86
|
if (/softprops\/action-gh-release/.test(content)) return true;
|
|
87
|
+
// Container + sigstore release tooling.
|
|
88
|
+
if (/\bko\s+(?:publish|build|apply|resolve)\b/.test(content)) return true;
|
|
89
|
+
if (/\bcosign\s+sign(?:-blob)?\b/.test(content)) return true;
|
|
90
|
+
if (/sigstore\/cosign-installer/.test(content)) return true;
|
|
91
|
+
if (/\bcrane\s+(?:push|copy|append)\b/.test(content)) return true;
|
|
92
|
+
if (/\boras\s+(?:push|copy)\b/.test(content)) return true;
|
|
93
|
+
// GitHub Container Registry / generic docker push paths.
|
|
94
|
+
if (/docker\/build-push-action/.test(content)) return true;
|
|
95
|
+
if (/\bdocker\s+push\b/.test(content)) return true;
|
|
96
|
+
// Sigstore OIDC token issuance is the canonical signal that a
|
|
97
|
+
// workflow is publishing artifacts — id-token: write inside a
|
|
98
|
+
// permissions block + the workflow runs more than a test job.
|
|
99
|
+
if (/id-token:\s*write/.test(content) && /\bsteps:/.test(content)) return true;
|
|
79
100
|
return false;
|
|
80
101
|
}
|
|
81
102
|
|
|
@@ -30,6 +30,34 @@ const DEFAULT_EXCLUDES = new Set([
|
|
|
30
30
|
"target", ".idea", ".vscode",
|
|
31
31
|
]);
|
|
32
32
|
|
|
33
|
+
// Path segments that denote test / fixture / example material. Hits
|
|
34
|
+
// scoped exclusively to these paths are downgraded — a private-key
|
|
35
|
+
// block in `cosign-test.key` or a JWT literal in `_test.go` is
|
|
36
|
+
// expected test material, not a real secret. If at least one hit
|
|
37
|
+
// exists outside these paths, the indicator still fires. Mirrors
|
|
38
|
+
// the crypto-codebase collector's isTestPath shape.
|
|
39
|
+
const TEST_PATH_SEGMENTS = [
|
|
40
|
+
"/test/", "/tests/", "/spec/", "/specs/", "/__tests__/",
|
|
41
|
+
"/fixtures/", "/fixture/", "/examples/", "/example/",
|
|
42
|
+
"/sample/", "/samples/", "/demo/", "/demos/",
|
|
43
|
+
"/testdata/", "/test-data/", "/test_data/",
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
function isTestPath(rel) {
|
|
47
|
+
const norm = "/" + rel.replace(/\\/g, "/").toLowerCase() + "/";
|
|
48
|
+
for (const seg of TEST_PATH_SEGMENTS) {
|
|
49
|
+
if (norm.includes(seg)) return true;
|
|
50
|
+
}
|
|
51
|
+
// foo.test.js / bar.spec.py — dot-separated convention.
|
|
52
|
+
if (/\.(test|spec)\.[a-z]+$/i.test(rel)) return true;
|
|
53
|
+
// foo_test.go (Go) / bar_test.py (some Python) — underscore convention.
|
|
54
|
+
if (/(?:^|[\\/])[^\\/]+_test\.[a-z]+$/i.test(rel)) return true;
|
|
55
|
+
// Files whose name itself includes the substring "test" before a
|
|
56
|
+
// key extension (e.g. cosign-test.key, github-test-token.json).
|
|
57
|
+
if (/-test[-.][^\\/]*$/i.test(rel)) return true;
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
|
|
33
61
|
const ENV_FILE_PREDICATE = (name) => {
|
|
34
62
|
if (name === ".env" || name === ".envrc") return true;
|
|
35
63
|
if (name.startsWith(".env.")) return true;
|
|
@@ -235,14 +263,32 @@ function collect({ cwd = process.cwd(), env = process.env, args = {} } = {}) {
|
|
|
235
263
|
}
|
|
236
264
|
}
|
|
237
265
|
|
|
266
|
+
// Split hits into production vs test-path. The indicator fires
|
|
267
|
+
// only when at least one PROD hit exists. Test-only hits stay in
|
|
268
|
+
// the artifact for operator inspection but don't flip the signal.
|
|
238
269
|
const hitsByIndicator = {};
|
|
270
|
+
const prodHitsByIndicator = {};
|
|
239
271
|
for (const h of allHits) {
|
|
240
272
|
(hitsByIndicator[h.indicator_id] = hitsByIndicator[h.indicator_id] || []).push(h);
|
|
273
|
+
if (!isTestPath(h.file)) {
|
|
274
|
+
(prodHitsByIndicator[h.indicator_id] = prodHitsByIndicator[h.indicator_id] || []).push(h);
|
|
275
|
+
}
|
|
241
276
|
}
|
|
277
|
+
// Same split for the file-presence indicators (ssh-private-keys
|
|
278
|
+
// artifact backs the ssh-private-key-block content scan AND the
|
|
279
|
+
// ssh-key-bad-perms posture check below). Filter out test-named
|
|
280
|
+
// private-key files (e.g. cosign-test.key) for the signal too.
|
|
281
|
+
const prodSshPrivateKeys = sshPrivateKeys.filter(f => !isTestPath(f.rel));
|
|
282
|
+
|
|
242
283
|
const signal_overrides = {};
|
|
243
284
|
for (const p of INDICATOR_PATTERNS) {
|
|
244
|
-
signal_overrides[p.id] =
|
|
285
|
+
signal_overrides[p.id] = prodHitsByIndicator[p.id] && prodHitsByIndicator[p.id].length > 0 ? "hit" : "miss";
|
|
245
286
|
}
|
|
287
|
+
// ssh-private-key-block is also flipped by file presence (a private
|
|
288
|
+
// key file with the matching magic bytes counts even without a
|
|
289
|
+
// content scan match — e.g. binary-only key formats). Re-flip when
|
|
290
|
+
// any non-test private-key file was discovered.
|
|
291
|
+
if (prodSshPrivateKeys.length > 0) signal_overrides["ssh-private-key-block"] = "hit";
|
|
246
292
|
// world-writable-env-file predicate (per data/playbooks/secrets.json):
|
|
247
293
|
// restricted to env-files artifact entries
|
|
248
294
|
// any .env / .env.* / .envrc with mode 0666 or 0664 (group/world writable)
|
package/manifest.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "exceptd-security",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.49",
|
|
4
4
|
"description": "AI security skills grounded in mid-2026 threat reality, not stale framework documentation",
|
|
5
5
|
"homepage": "https://exceptd.com",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
],
|
|
54
54
|
"last_threat_review": "2026-05-01",
|
|
55
55
|
"signature": "lXhZgoIrrVloO3XaTvo/43AxZn4mwErstd7DR0O/oVhD3AOGODM4HqrageYEou9WKOdMEGP5mJNTjJsXdP5NDA==",
|
|
56
|
-
"signed_at": "2026-05-
|
|
56
|
+
"signed_at": "2026-05-21T17:36:00.089Z",
|
|
57
57
|
"cwe_refs": [
|
|
58
58
|
"CWE-125",
|
|
59
59
|
"CWE-362",
|
|
@@ -117,7 +117,7 @@
|
|
|
117
117
|
],
|
|
118
118
|
"last_threat_review": "2026-05-01",
|
|
119
119
|
"signature": "vSVqu4wBm+d68ujZmM6Rto/HzViCkE0gPUcv/MYE/bjFiqamf/s0On4kTOo1KIveV9cOwYNxiItaGEWlVkRFDg==",
|
|
120
|
-
"signed_at": "2026-05-
|
|
120
|
+
"signed_at": "2026-05-21T17:36:00.091Z",
|
|
121
121
|
"cwe_refs": [
|
|
122
122
|
"CWE-1039",
|
|
123
123
|
"CWE-1426",
|
|
@@ -180,7 +180,7 @@
|
|
|
180
180
|
],
|
|
181
181
|
"last_threat_review": "2026-05-01",
|
|
182
182
|
"signature": "RIgXKvolQjgJdnlrDnVOd90IOY1B7VHHZD/YJQRzouL+wUeOLclPrdK/EgEuFyiu7lR4bi+Pl6aGB9G9tOxYCQ==",
|
|
183
|
-
"signed_at": "2026-05-
|
|
183
|
+
"signed_at": "2026-05-21T17:36:00.091Z",
|
|
184
184
|
"cwe_refs": [
|
|
185
185
|
"CWE-22",
|
|
186
186
|
"CWE-345",
|
|
@@ -226,7 +226,7 @@
|
|
|
226
226
|
"framework_gaps": [],
|
|
227
227
|
"last_threat_review": "2026-05-01",
|
|
228
228
|
"signature": "RYOxeq/o3uTwTWq4H7RcdH2Aclg9UyCERfUH9Frwkzncsowg7LgxpaEDc3swTCv73HMEGbU8wVbXguZ4JxHUCQ==",
|
|
229
|
-
"signed_at": "2026-05-
|
|
229
|
+
"signed_at": "2026-05-21T17:36:00.092Z"
|
|
230
230
|
},
|
|
231
231
|
{
|
|
232
232
|
"name": "compliance-theater",
|
|
@@ -257,7 +257,7 @@
|
|
|
257
257
|
],
|
|
258
258
|
"last_threat_review": "2026-05-01",
|
|
259
259
|
"signature": "DneJCPKCPcoe6nQ82XptqSqNfSRdt1orKaO+o7K36YCciDrzwJb+1BuBLusPDtpcdDaGY0y0e+AqiTYJklhBAQ==",
|
|
260
|
-
"signed_at": "2026-05-
|
|
260
|
+
"signed_at": "2026-05-21T17:36:00.092Z"
|
|
261
261
|
},
|
|
262
262
|
{
|
|
263
263
|
"name": "exploit-scoring",
|
|
@@ -286,7 +286,7 @@
|
|
|
286
286
|
],
|
|
287
287
|
"last_threat_review": "2026-05-01",
|
|
288
288
|
"signature": "NA1hoQycvQhSUoG5rwlXX0mOVmGxoXRVezkELGEA2nZOdGis4gXkHT3O6Sfw7zxE4JuMrsCb65TEeOWk9WEPDg==",
|
|
289
|
-
"signed_at": "2026-05-
|
|
289
|
+
"signed_at": "2026-05-21T17:36:00.093Z"
|
|
290
290
|
},
|
|
291
291
|
{
|
|
292
292
|
"name": "rag-pipeline-security",
|
|
@@ -323,7 +323,7 @@
|
|
|
323
323
|
],
|
|
324
324
|
"last_threat_review": "2026-05-01",
|
|
325
325
|
"signature": "XgrzcA2brPhXrSTxrcLnJec0OpgGYJBoSTUlJ10UdePHffxqb9LTVGnfbmEk1ykQifXREZexui2bG7X/+eFfCQ==",
|
|
326
|
-
"signed_at": "2026-05-
|
|
326
|
+
"signed_at": "2026-05-21T17:36:00.094Z",
|
|
327
327
|
"cwe_refs": [
|
|
328
328
|
"CWE-1395",
|
|
329
329
|
"CWE-1426"
|
|
@@ -380,7 +380,7 @@
|
|
|
380
380
|
],
|
|
381
381
|
"last_threat_review": "2026-05-01",
|
|
382
382
|
"signature": "9+hZlZOqZdeACUmamQk66L5levZhhwnFXuYRhdT6Mce99eQaKT7wNfWq12hXQztkRcVRKaFH+a01zwJQwsRQCA==",
|
|
383
|
-
"signed_at": "2026-05-
|
|
383
|
+
"signed_at": "2026-05-21T17:36:00.094Z",
|
|
384
384
|
"d3fend_refs": [
|
|
385
385
|
"D3-CA",
|
|
386
386
|
"D3-CSPP",
|
|
@@ -415,7 +415,7 @@
|
|
|
415
415
|
"framework_gaps": [],
|
|
416
416
|
"last_threat_review": "2026-05-01",
|
|
417
417
|
"signature": "ciqhVloMWWXEigPZvvwoV2c54tEqsDqsoc+sS/mNTFFJk2H+tz2+XUrgfEPRuYw0FeyNB6/+27pL2NpKHzUqAg==",
|
|
418
|
-
"signed_at": "2026-05-
|
|
418
|
+
"signed_at": "2026-05-21T17:36:00.095Z",
|
|
419
419
|
"cwe_refs": [
|
|
420
420
|
"CWE-1188"
|
|
421
421
|
]
|
|
@@ -443,7 +443,7 @@
|
|
|
443
443
|
"framework_gaps": [],
|
|
444
444
|
"last_threat_review": "2026-05-01",
|
|
445
445
|
"signature": "xiHAhhdufm9hCKU8PLiPE0MX65ej2F4OZwtlWLGLCiie9/km+Kiqbt192LcMvr94v83C98pb9wIaqFsFWft6AQ==",
|
|
446
|
-
"signed_at": "2026-05-
|
|
446
|
+
"signed_at": "2026-05-21T17:36:00.095Z"
|
|
447
447
|
},
|
|
448
448
|
{
|
|
449
449
|
"name": "global-grc",
|
|
@@ -475,7 +475,7 @@
|
|
|
475
475
|
"framework_gaps": [],
|
|
476
476
|
"last_threat_review": "2026-05-01",
|
|
477
477
|
"signature": "oYsSk35N2Uzq7MRofACykylcVwkgPhI4luWZ14vmQT+gUKLyZiKVOUJbe1+7lGl6BYPRN0sUDQ0f7S5Eu5w2Ag==",
|
|
478
|
-
"signed_at": "2026-05-
|
|
478
|
+
"signed_at": "2026-05-21T17:36:00.095Z"
|
|
479
479
|
},
|
|
480
480
|
{
|
|
481
481
|
"name": "zeroday-gap-learn",
|
|
@@ -502,7 +502,7 @@
|
|
|
502
502
|
"framework_gaps": [],
|
|
503
503
|
"last_threat_review": "2026-05-01",
|
|
504
504
|
"signature": "igRqYyU1unRFH40BsPyAR62SPrk8QZv8dPGb8S9O9EvLCNOZAzm3t+HdT/NKqzWHwrpomOzkkkyLfYI/0qTUDA==",
|
|
505
|
-
"signed_at": "2026-05-
|
|
505
|
+
"signed_at": "2026-05-21T17:36:00.096Z"
|
|
506
506
|
},
|
|
507
507
|
{
|
|
508
508
|
"name": "pqc-first",
|
|
@@ -554,7 +554,7 @@
|
|
|
554
554
|
],
|
|
555
555
|
"last_threat_review": "2026-05-01",
|
|
556
556
|
"signature": "vhc3wuQEro/86s1ro2b/KakUXg8QVnySYTBqA7ebzv9oeR2HYO5bvGEJp3oOHWtL37JDqcCAHYadSN/qxIyCCA==",
|
|
557
|
-
"signed_at": "2026-05-
|
|
557
|
+
"signed_at": "2026-05-21T17:36:00.096Z",
|
|
558
558
|
"cwe_refs": [
|
|
559
559
|
"CWE-327"
|
|
560
560
|
],
|
|
@@ -601,7 +601,7 @@
|
|
|
601
601
|
],
|
|
602
602
|
"last_threat_review": "2026-05-01",
|
|
603
603
|
"signature": "MS35nWm8djfJGn4OOoT0JKJ2aO+Dkbb6wOOWJYvNZlRKT3UGA59o2gxg1JOnD20hb/RwxtkmCujhl2tuYSR+AQ==",
|
|
604
|
-
"signed_at": "2026-05-
|
|
604
|
+
"signed_at": "2026-05-21T17:36:00.097Z"
|
|
605
605
|
},
|
|
606
606
|
{
|
|
607
607
|
"name": "security-maturity-tiers",
|
|
@@ -638,7 +638,7 @@
|
|
|
638
638
|
],
|
|
639
639
|
"last_threat_review": "2026-05-01",
|
|
640
640
|
"signature": "8Px1s2lDj10/Q6erwEQlXgUHM1+OTruUR8qAHPX7Oo3k/l69N6P9sm0PsafS9wDFtj9l5C/OiLiFgzMlMt6vBw==",
|
|
641
|
-
"signed_at": "2026-05-
|
|
641
|
+
"signed_at": "2026-05-21T17:36:00.097Z",
|
|
642
642
|
"cwe_refs": [
|
|
643
643
|
"CWE-1188"
|
|
644
644
|
]
|
|
@@ -673,7 +673,7 @@
|
|
|
673
673
|
"framework_gaps": [],
|
|
674
674
|
"last_threat_review": "2026-05-11",
|
|
675
675
|
"signature": "WAu5fRirzSOcnnZsTx2d/JJZwa/LPpXCi+31qATTGLmoNuhyy81k3ooPe9kCM3E0CLMtvTePg9DagYqBninZDQ==",
|
|
676
|
-
"signed_at": "2026-05-
|
|
676
|
+
"signed_at": "2026-05-21T17:36:00.097Z"
|
|
677
677
|
},
|
|
678
678
|
{
|
|
679
679
|
"name": "attack-surface-pentest",
|
|
@@ -744,7 +744,7 @@
|
|
|
744
744
|
"PTES revision incorporating AI-surface enumeration"
|
|
745
745
|
],
|
|
746
746
|
"signature": "7eEwCXFd9pDKUw7yCUbRJSjfzozE44dwwwemCQUPm8JBPztLltibD9bL/RszSbYyCrYJmVb5Drncz2cGe62gCw==",
|
|
747
|
-
"signed_at": "2026-05-
|
|
747
|
+
"signed_at": "2026-05-21T17:36:00.098Z"
|
|
748
748
|
},
|
|
749
749
|
{
|
|
750
750
|
"name": "fuzz-testing-strategy",
|
|
@@ -804,7 +804,7 @@
|
|
|
804
804
|
"OSS-Fuzz-Gen / AI-assisted harness generation becoming the default expectation for OSS maintainers"
|
|
805
805
|
],
|
|
806
806
|
"signature": "Z7ypCUnXx8JpLtgxxB6RHNi39w74AmrGY1N4ofAGCXhkuM2EaFVm1AU0dvl9UQ1bVLfHKEDGqMO/TwlIY7RABg==",
|
|
807
|
-
"signed_at": "2026-05-
|
|
807
|
+
"signed_at": "2026-05-21T17:36:00.098Z"
|
|
808
808
|
},
|
|
809
809
|
{
|
|
810
810
|
"name": "dlp-gap-analysis",
|
|
@@ -879,7 +879,7 @@
|
|
|
879
879
|
"Quebec Law 25, India DPDPA, KSA PDPL enforcement actions naming AI-tool prompt data as in-scope personal information"
|
|
880
880
|
],
|
|
881
881
|
"signature": "fgxG344JGYBWWWwFXZ1IzGipWKP7EyBhrsvsbsb0CCGXfv/MvNHVNI6G0zQddCsWX1JeQbhZT3Vk8v1uJKDTDA==",
|
|
882
|
-
"signed_at": "2026-05-
|
|
882
|
+
"signed_at": "2026-05-21T17:36:00.098Z"
|
|
883
883
|
},
|
|
884
884
|
{
|
|
885
885
|
"name": "supply-chain-integrity",
|
|
@@ -956,7 +956,7 @@
|
|
|
956
956
|
"OpenSSF model-signing — emerging Sigstore-based signing standard for ML model weights; track for production adoption"
|
|
957
957
|
],
|
|
958
958
|
"signature": "pcLrM98A3vUSZRjwNAk0aZ9umvOwB41XCLLsCOy/IebB2F/06oIrGUKkMHtHwm4pTVPShMMcKdZQQ3jz30FnCg==",
|
|
959
|
-
"signed_at": "2026-05-
|
|
959
|
+
"signed_at": "2026-05-21T17:36:00.099Z"
|
|
960
960
|
},
|
|
961
961
|
{
|
|
962
962
|
"name": "defensive-countermeasure-mapping",
|
|
@@ -1013,7 +1013,7 @@
|
|
|
1013
1013
|
],
|
|
1014
1014
|
"last_threat_review": "2026-05-11",
|
|
1015
1015
|
"signature": "gqF8eU3VBrZhO2WnlcqKa7wm1d2mmWtvpbmx0kNCgHojNV+qEt+Ij84RO6bZvaUqhfYPWizWL79Fa4DL0curAQ==",
|
|
1016
|
-
"signed_at": "2026-05-
|
|
1016
|
+
"signed_at": "2026-05-21T17:36:00.099Z"
|
|
1017
1017
|
},
|
|
1018
1018
|
{
|
|
1019
1019
|
"name": "identity-assurance",
|
|
@@ -1080,7 +1080,7 @@
|
|
|
1080
1080
|
"d3fend_refs": [],
|
|
1081
1081
|
"last_threat_review": "2026-05-11",
|
|
1082
1082
|
"signature": "Wv5hGMeHjlaQK1zwicVCA7AvdKgJBgvcjdpGM9Ywahh9tagAKhbkOjybowDQZzu7OZ3bDkbh6pBYc1Sdwr6NAA==",
|
|
1083
|
-
"signed_at": "2026-05-
|
|
1083
|
+
"signed_at": "2026-05-21T17:36:00.099Z"
|
|
1084
1084
|
},
|
|
1085
1085
|
{
|
|
1086
1086
|
"name": "ot-ics-security",
|
|
@@ -1136,7 +1136,7 @@
|
|
|
1136
1136
|
"d3fend_refs": [],
|
|
1137
1137
|
"last_threat_review": "2026-05-11",
|
|
1138
1138
|
"signature": "8t5qKHd3yWi57dvG36YQkLN/X9bQWqtEiYjay4IfSmqhJpM/xXPaQVKNGz3wscrO8OLKUZ0OaX7Mj5kzpgBKBQ==",
|
|
1139
|
-
"signed_at": "2026-05-
|
|
1139
|
+
"signed_at": "2026-05-21T17:36:00.100Z"
|
|
1140
1140
|
},
|
|
1141
1141
|
{
|
|
1142
1142
|
"name": "coordinated-vuln-disclosure",
|
|
@@ -1188,7 +1188,7 @@
|
|
|
1188
1188
|
"NYDFS 23 NYCRR 500 amendments potentially adding explicit CVD program requirements"
|
|
1189
1189
|
],
|
|
1190
1190
|
"signature": "GDGt4UPqBa04PjlpSmpyihGzd3OgfBN7jaAK5tfwp+LRSs3ygKOdbeivUCCHNagTY1hE6hG2Ou40ADfBFuXeAg==",
|
|
1191
|
-
"signed_at": "2026-05-
|
|
1191
|
+
"signed_at": "2026-05-21T17:36:00.100Z"
|
|
1192
1192
|
},
|
|
1193
1193
|
{
|
|
1194
1194
|
"name": "threat-modeling-methodology",
|
|
@@ -1238,7 +1238,7 @@
|
|
|
1238
1238
|
"PASTA v2 updates incorporating AI/ML application threats"
|
|
1239
1239
|
],
|
|
1240
1240
|
"signature": "rFBpOQEJUPpl+v88Lw/WqVJRhTl80vy0VbPAbzQj3Q0suJRRrJg368I9uKu5LXIBKFDvKxnGIcIzbGg9NUtaCA==",
|
|
1241
|
-
"signed_at": "2026-05-
|
|
1241
|
+
"signed_at": "2026-05-21T17:36:00.100Z"
|
|
1242
1242
|
},
|
|
1243
1243
|
{
|
|
1244
1244
|
"name": "webapp-security",
|
|
@@ -1312,7 +1312,7 @@
|
|
|
1312
1312
|
"d3fend_refs": [],
|
|
1313
1313
|
"last_threat_review": "2026-05-11",
|
|
1314
1314
|
"signature": "ux85YI4t2mVHOyt744Yin1HHy+z11JIFygjKfFfQOBBl5QVV3A267jeIy7utix85irMcpZm/T3yx/ooqiK2tBA==",
|
|
1315
|
-
"signed_at": "2026-05-
|
|
1315
|
+
"signed_at": "2026-05-21T17:36:00.101Z"
|
|
1316
1316
|
},
|
|
1317
1317
|
{
|
|
1318
1318
|
"name": "ai-risk-management",
|
|
@@ -1362,7 +1362,7 @@
|
|
|
1362
1362
|
"d3fend_refs": [],
|
|
1363
1363
|
"last_threat_review": "2026-05-11",
|
|
1364
1364
|
"signature": "IIXnkZ5ZNqFwOto5KfytADTLLZLoyXNZACD1ORZ40P1HUAQxe6u2uyXFzzsfuob4Uy06jNkRGr2FFgCphUH1Cw==",
|
|
1365
|
-
"signed_at": "2026-05-
|
|
1365
|
+
"signed_at": "2026-05-21T17:36:00.101Z"
|
|
1366
1366
|
},
|
|
1367
1367
|
{
|
|
1368
1368
|
"name": "sector-healthcare",
|
|
@@ -1422,7 +1422,7 @@
|
|
|
1422
1422
|
"d3fend_refs": [],
|
|
1423
1423
|
"last_threat_review": "2026-05-11",
|
|
1424
1424
|
"signature": "AhF9KF8ZBlDteciV+F8IBSmFVYCvQOn44GmD4rZjgLoPxfIv/QE1/vSkK32zyqDKtHWkLSXExbkkPkxA/V6dDw==",
|
|
1425
|
-
"signed_at": "2026-05-
|
|
1425
|
+
"signed_at": "2026-05-21T17:36:00.102Z"
|
|
1426
1426
|
},
|
|
1427
1427
|
{
|
|
1428
1428
|
"name": "sector-financial",
|
|
@@ -1503,7 +1503,7 @@
|
|
|
1503
1503
|
"TIBER-EU framework v2.0 alignment with DORA TLPT RTS (JC 2024/40); cross-recognition with CBEST and iCAST"
|
|
1504
1504
|
],
|
|
1505
1505
|
"signature": "HQgZvb4ReziEz5rNFr8i/O8/rJEZR+iHRROT7m/D2QUqhrcNISPkYXENsUZlG8xapzy/Ik92ehkseyj4hdmhCQ==",
|
|
1506
|
-
"signed_at": "2026-05-
|
|
1506
|
+
"signed_at": "2026-05-21T17:36:00.102Z"
|
|
1507
1507
|
},
|
|
1508
1508
|
{
|
|
1509
1509
|
"name": "sector-federal-government",
|
|
@@ -1572,7 +1572,7 @@
|
|
|
1572
1572
|
"Australia PSPF 2024 revision and ISM quarterly updates — track for Essential Eight Maturity Level requirements for federal entities"
|
|
1573
1573
|
],
|
|
1574
1574
|
"signature": "linxmsXZiOYtcs71sSWgGCrvb8xQfmxmtTY5PRvZJ0/8FgJulo0tQtejzexYG775s7XhjAmGsDP238BQTQ8ADA==",
|
|
1575
|
-
"signed_at": "2026-05-
|
|
1575
|
+
"signed_at": "2026-05-21T17:36:00.103Z"
|
|
1576
1576
|
},
|
|
1577
1577
|
{
|
|
1578
1578
|
"name": "sector-energy",
|
|
@@ -1637,7 +1637,7 @@
|
|
|
1637
1637
|
"ICS-CERT advisory feed (https://www.cisa.gov/news-events/cybersecurity-advisories/ics-advisories) for vendor CVEs in Siemens, Rockwell, Schneider Electric, ABB, GE Vernova, Hitachi Energy, AVEVA / OSIsoft PI"
|
|
1638
1638
|
],
|
|
1639
1639
|
"signature": "JjBfc0ovta560Clk0x3QGRM5osFJDwcvpy3rT7QEGdCIL827jzE8QCow1C8deXq+4JhY2sA/d7/8IsxikdlkCg==",
|
|
1640
|
-
"signed_at": "2026-05-
|
|
1640
|
+
"signed_at": "2026-05-21T17:36:00.103Z"
|
|
1641
1641
|
},
|
|
1642
1642
|
{
|
|
1643
1643
|
"name": "sector-telecom",
|
|
@@ -1723,7 +1723,7 @@
|
|
|
1723
1723
|
"O-RAN SFG / WG11 security specifications"
|
|
1724
1724
|
],
|
|
1725
1725
|
"signature": "JWVxKFoKrbX4d+Tko1d4OBdwyg25MfFFKn4CT6E/CzH+YwnU3T6Y76uBQIKg3+gIGTvPduqyvQwQQ5FxKDuPBw==",
|
|
1726
|
-
"signed_at": "2026-05-
|
|
1726
|
+
"signed_at": "2026-05-21T17:36:00.103Z"
|
|
1727
1727
|
},
|
|
1728
1728
|
{
|
|
1729
1729
|
"name": "api-security",
|
|
@@ -1792,7 +1792,7 @@
|
|
|
1792
1792
|
"d3fend_refs": [],
|
|
1793
1793
|
"last_threat_review": "2026-05-11",
|
|
1794
1794
|
"signature": "BmCRCestWqr55+fCynEhtAl5NWLT+xLTkpwS0Icp3SaoZOw/ce3Y6TtqjHRSKn4CBJq7YDiLRWxmhO3MStvOAA==",
|
|
1795
|
-
"signed_at": "2026-05-
|
|
1795
|
+
"signed_at": "2026-05-21T17:36:00.104Z"
|
|
1796
1796
|
},
|
|
1797
1797
|
{
|
|
1798
1798
|
"name": "cloud-security",
|
|
@@ -1873,7 +1873,7 @@
|
|
|
1873
1873
|
"CISA KEV additions for cloud-control-plane CVEs (IMDSv1 abuses, federation token mishandling, cross-tenant boundary failures); CISA Cybersecurity Advisories for cross-cloud advisories"
|
|
1874
1874
|
],
|
|
1875
1875
|
"signature": "/DV3pmZwrRySrk1OCbyI+0BQESacjupJfUX3eC2NGtXuYOBro0vndIP+z27heFxumnjU3a9sfla7/U9X+pqnDw==",
|
|
1876
|
-
"signed_at": "2026-05-
|
|
1876
|
+
"signed_at": "2026-05-21T17:36:00.104Z"
|
|
1877
1877
|
},
|
|
1878
1878
|
{
|
|
1879
1879
|
"name": "container-runtime-security",
|
|
@@ -1935,7 +1935,7 @@
|
|
|
1935
1935
|
"d3fend_refs": [],
|
|
1936
1936
|
"last_threat_review": "2026-05-11",
|
|
1937
1937
|
"signature": "E2UGSf9ATyYgzBr8uM/0ubOUmDqo1jVA7f9mVxv6LHfWGCNuQNXDyuNou9VAmUCeeXEeUYIi3AFjXkJqpOkxDA==",
|
|
1938
|
-
"signed_at": "2026-05-
|
|
1938
|
+
"signed_at": "2026-05-21T17:36:00.104Z"
|
|
1939
1939
|
},
|
|
1940
1940
|
{
|
|
1941
1941
|
"name": "mlops-security",
|
|
@@ -2006,7 +2006,7 @@
|
|
|
2006
2006
|
"MITRE ATLAS v5.6.0 (released February 2026) shipped the AML.T0010 sub-technique expansion this forecast tracked plus new techniques (\"Publish Poisoned AI Agent Tool\", \"Escape to Host\"); inventory now 16 tactics, 84 techniques, 56 sub-techniques. Forward watch: ATLAS v5.5 / v6.0 — track next-cadence updates to agentic-AI TTPs and MLOps-pipeline-specific techniques"
|
|
2007
2007
|
],
|
|
2008
2008
|
"signature": "BGNE6ZQWBA1LmsUFe8tU0L67iGDSrFqiuqaZD2f1KqfcyqqzQfMs9PWNHFzxxaJmXeKlm87eU8lgELF0bX+RBA==",
|
|
2009
|
-
"signed_at": "2026-05-
|
|
2009
|
+
"signed_at": "2026-05-21T17:36:00.105Z"
|
|
2010
2010
|
},
|
|
2011
2011
|
{
|
|
2012
2012
|
"name": "incident-response-playbook",
|
|
@@ -2068,7 +2068,7 @@
|
|
|
2068
2068
|
"NYDFS 23 NYCRR 500.17 amendments tightening ransom-payment 24h disclosure operationalization"
|
|
2069
2069
|
],
|
|
2070
2070
|
"signature": "FkZQerh3VHVJAwIcCktDyMRh5KE2+Em/i0ek8zEz7JG/PXtQx8ujHWTh3VjZbOLhPNtdB2qxgXOIAYIofaVOAQ==",
|
|
2071
|
-
"signed_at": "2026-05-
|
|
2071
|
+
"signed_at": "2026-05-21T17:36:00.105Z"
|
|
2072
2072
|
},
|
|
2073
2073
|
{
|
|
2074
2074
|
"name": "ransomware-response",
|
|
@@ -2148,7 +2148,7 @@
|
|
|
2148
2148
|
],
|
|
2149
2149
|
"last_threat_review": "2026-05-15",
|
|
2150
2150
|
"signature": "n3UToNuN3A1HgLvcuqmIx8vrZY71+r/79waK92jG+rSX4uYOzkmxMUpROrE5K9bDwMezNBHdjWv8Uul6zugyDQ==",
|
|
2151
|
-
"signed_at": "2026-05-
|
|
2151
|
+
"signed_at": "2026-05-21T17:36:00.105Z"
|
|
2152
2152
|
},
|
|
2153
2153
|
{
|
|
2154
2154
|
"name": "email-security-anti-phishing",
|
|
@@ -2201,7 +2201,7 @@
|
|
|
2201
2201
|
"d3fend_refs": [],
|
|
2202
2202
|
"last_threat_review": "2026-05-11",
|
|
2203
2203
|
"signature": "rK+WnuS+9tqEABmwc0jO/PEmxcLjG1/tmUb897HsClQeKzf+TQOlwBE+OsbtuKxpjYNwur62Xxs3TxObkwm8Cw==",
|
|
2204
|
-
"signed_at": "2026-05-
|
|
2204
|
+
"signed_at": "2026-05-21T17:36:00.106Z"
|
|
2205
2205
|
},
|
|
2206
2206
|
{
|
|
2207
2207
|
"name": "age-gates-child-safety",
|
|
@@ -2269,7 +2269,7 @@
|
|
|
2269
2269
|
"US state adult-site age-verification laws — 19+ states by mid-2026 (TX HB 18 upheld by SCOTUS June 2025 in Free Speech Coalition v. Paxton); track ongoing challenges in remaining states"
|
|
2270
2270
|
],
|
|
2271
2271
|
"signature": "+OO0RhQ303RJV7kaH38IuZpLeQbapep6Ds4Re/WEZu0FHBwKSlwvF7jbtP7KQ57xldJYn/xZm2jaszyOacMfDg==",
|
|
2272
|
-
"signed_at": "2026-05-
|
|
2272
|
+
"signed_at": "2026-05-21T17:36:00.106Z"
|
|
2273
2273
|
},
|
|
2274
2274
|
{
|
|
2275
2275
|
"name": "cloud-iam-incident",
|
|
@@ -2349,7 +2349,7 @@
|
|
|
2349
2349
|
],
|
|
2350
2350
|
"last_threat_review": "2026-05-15",
|
|
2351
2351
|
"signature": "e/kij7GtKaytROyIj7V5RH+FC9WtmVFzrmG2kIlNDNn29ep/CRNlIQKwXLpzo/81AIf634pmdr1qy/+vwIuUDA==",
|
|
2352
|
-
"signed_at": "2026-05-
|
|
2352
|
+
"signed_at": "2026-05-21T17:36:00.107Z"
|
|
2353
2353
|
},
|
|
2354
2354
|
{
|
|
2355
2355
|
"name": "idp-incident-response",
|
|
@@ -2430,11 +2430,11 @@
|
|
|
2430
2430
|
],
|
|
2431
2431
|
"last_threat_review": "2026-05-15",
|
|
2432
2432
|
"signature": "ew9Kglc9fAZzbn0ZIfGP7WSK/j4eV2VhSvpy+s5bEfNEVYIMa2kZjnGBapgUsyGDLes9H9K2ovjQyX17+GKiBw==",
|
|
2433
|
-
"signed_at": "2026-05-
|
|
2433
|
+
"signed_at": "2026-05-21T17:36:00.107Z"
|
|
2434
2434
|
}
|
|
2435
2435
|
],
|
|
2436
2436
|
"manifest_signature": {
|
|
2437
2437
|
"algorithm": "Ed25519",
|
|
2438
|
-
"signature_base64": "
|
|
2438
|
+
"signature_base64": "fh1K2ANMsPzZTwxkm31oVK6WRuY7P0h/LpomKgFhakAA4qDAfTVAy6lk1PcaqIMgX6okxOwMgcdKQFHC0XQuBw=="
|
|
2439
2439
|
}
|
|
2440
2440
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blamejs/exceptd-skills",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.49",
|
|
4
4
|
"description": "AI security skills grounded in mid-2026 threat reality, not stale framework documentation. 42 skills, 10 catalogs (312 CVEs / 171 CWEs / 805 ATT&CK + ICS / 170 ATLAS / 468 D3FEND / 7476 RFCs), 34 jurisdictions, 10-class catalog gap detector + budget gate, real XML parser + canonical-form diff + content-pattern regression detection, Ed25519-signed.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai-security",
|
package/sbom.cdx.json
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"bomFormat": "CycloneDX",
|
|
3
3
|
"specVersion": "1.6",
|
|
4
|
-
"serialNumber": "urn:uuid:
|
|
4
|
+
"serialNumber": "urn:uuid:3d203982-8322-49a5-9822-36f3e578614d",
|
|
5
5
|
"version": 1,
|
|
6
6
|
"metadata": {
|
|
7
|
-
"timestamp": "
|
|
7
|
+
"timestamp": "2058-07-01T11:14:10.000Z",
|
|
8
8
|
"tools": [
|
|
9
9
|
{
|
|
10
10
|
"vendor": "blamejs",
|
|
11
11
|
"name": "scripts/refresh-sbom.js",
|
|
12
|
-
"version": "0.13.
|
|
12
|
+
"version": "0.13.49"
|
|
13
13
|
}
|
|
14
14
|
],
|
|
15
15
|
"component": {
|
|
16
|
-
"bom-ref": "pkg:npm/@blamejs/exceptd-skills@0.13.
|
|
16
|
+
"bom-ref": "pkg:npm/@blamejs/exceptd-skills@0.13.49",
|
|
17
17
|
"type": "application",
|
|
18
18
|
"name": "@blamejs/exceptd-skills",
|
|
19
|
-
"version": "0.13.
|
|
19
|
+
"version": "0.13.49",
|
|
20
20
|
"description": "AI security skills grounded in mid-2026 threat reality, not stale framework documentation. 42 skills, 10 catalogs (312 CVEs / 171 CWEs / 805 ATT&CK + ICS / 170 ATLAS / 468 D3FEND / 7476 RFCs), 34 jurisdictions, 10-class catalog gap detector + budget gate, real XML parser + canonical-form diff + content-pattern regression detection, Ed25519-signed.",
|
|
21
21
|
"licenses": [
|
|
22
22
|
{
|
|
@@ -25,17 +25,17 @@
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
],
|
|
28
|
-
"purl": "pkg:npm/%40blamejs/exceptd-skills@0.13.
|
|
28
|
+
"purl": "pkg:npm/%40blamejs/exceptd-skills@0.13.49",
|
|
29
29
|
"hashes": [
|
|
30
30
|
{
|
|
31
31
|
"alg": "SHA-256",
|
|
32
|
-
"content": "
|
|
32
|
+
"content": "0cc0239379aa675d66a79fd4927e165df684aa8b16274779c1ade7cea6ef988f"
|
|
33
33
|
}
|
|
34
34
|
],
|
|
35
35
|
"externalReferences": [
|
|
36
36
|
{
|
|
37
37
|
"type": "distribution",
|
|
38
|
-
"url": "https://www.npmjs.com/package/@blamejs/exceptd-skills/v/0.13.
|
|
38
|
+
"url": "https://www.npmjs.com/package/@blamejs/exceptd-skills/v/0.13.49"
|
|
39
39
|
},
|
|
40
40
|
{
|
|
41
41
|
"type": "vcs",
|
|
@@ -116,11 +116,11 @@
|
|
|
116
116
|
"hashes": [
|
|
117
117
|
{
|
|
118
118
|
"alg": "SHA-256",
|
|
119
|
-
"content": "
|
|
119
|
+
"content": "d93a2bbbafc6fe57f582c4ef06504eb172d09ed556281bcdb429d0b4d386eb00"
|
|
120
120
|
},
|
|
121
121
|
{
|
|
122
122
|
"alg": "SHA3-512",
|
|
123
|
-
"content": "
|
|
123
|
+
"content": "9339c6c17243ad1b2f9821f3f31c722cabc896377eaa254606207a4438ddaaf9a4342745fdddfc512721b78a3e4ee21b20cf814f7d6602656e1ae3a0ad526ba6"
|
|
124
124
|
}
|
|
125
125
|
]
|
|
126
126
|
},
|
|
@@ -281,11 +281,11 @@
|
|
|
281
281
|
"hashes": [
|
|
282
282
|
{
|
|
283
283
|
"alg": "SHA-256",
|
|
284
|
-
"content": "
|
|
284
|
+
"content": "605b1d6cbaf1e8fea9937c0f41f9cc17a630300bd3dd8a3c425fe1885775d380"
|
|
285
285
|
},
|
|
286
286
|
{
|
|
287
287
|
"alg": "SHA3-512",
|
|
288
|
-
"content": "
|
|
288
|
+
"content": "6dd90b9c957cfeb05c626e3ed175a5700f534dd4422b812f66cb72856f23d371d0d8eb2801a76f5a445ba17e4750259791ccd3bd7a8648e92f8e31a962245ff6"
|
|
289
289
|
}
|
|
290
290
|
]
|
|
291
291
|
},
|
|
@@ -926,11 +926,11 @@
|
|
|
926
926
|
"hashes": [
|
|
927
927
|
{
|
|
928
928
|
"alg": "SHA-256",
|
|
929
|
-
"content": "
|
|
929
|
+
"content": "ca9fe6c5613c36cd7b7b016863f76b6081284847d7a519b54354e8b428542eb4"
|
|
930
930
|
},
|
|
931
931
|
{
|
|
932
932
|
"alg": "SHA3-512",
|
|
933
|
-
"content": "
|
|
933
|
+
"content": "07658edb8e5d00b7fd2a67c0d3166074251521d7821210f8f28226fd02108c7b8a8980f0ff573b82350bef2afe2d5f53d02dbee8aae41be01db7f6fbf4ae6d19"
|
|
934
934
|
}
|
|
935
935
|
]
|
|
936
936
|
},
|
|
@@ -941,11 +941,11 @@
|
|
|
941
941
|
"hashes": [
|
|
942
942
|
{
|
|
943
943
|
"alg": "SHA-256",
|
|
944
|
-
"content": "
|
|
944
|
+
"content": "abc9ed4ffe582d4f1ab32fe4d964ae29c59bba0ef8fcfab6c94097e8f82569a7"
|
|
945
945
|
},
|
|
946
946
|
{
|
|
947
947
|
"alg": "SHA3-512",
|
|
948
|
-
"content": "
|
|
948
|
+
"content": "a110cb3d582c78e6fb0793371606d38a0ed62cd0d84b9d454878931113485a10a9729283205256365bb43f96d6daee5f727777c673d8701a0ca8da5c8b99b973"
|
|
949
949
|
}
|
|
950
950
|
]
|
|
951
951
|
},
|
|
@@ -1001,11 +1001,11 @@
|
|
|
1001
1001
|
"hashes": [
|
|
1002
1002
|
{
|
|
1003
1003
|
"alg": "SHA-256",
|
|
1004
|
-
"content": "
|
|
1004
|
+
"content": "3b9eb4b785889d4b1416d4bcf3e234bfdad635297d460cf64d934e257d139704"
|
|
1005
1005
|
},
|
|
1006
1006
|
{
|
|
1007
1007
|
"alg": "SHA3-512",
|
|
1008
|
-
"content": "
|
|
1008
|
+
"content": "11c1d492d7e15da9e5e3f5ffce72cb1e002970a5a23be650da8506a61447bf988bc2da8deea9300ffe2e81ceb4f39abf9d48ea2b2224712835675cbc39d1a4d2"
|
|
1009
1009
|
}
|
|
1010
1010
|
]
|
|
1011
1011
|
},
|
|
@@ -1061,11 +1061,11 @@
|
|
|
1061
1061
|
"hashes": [
|
|
1062
1062
|
{
|
|
1063
1063
|
"alg": "SHA-256",
|
|
1064
|
-
"content": "
|
|
1064
|
+
"content": "33456838e7363a51fcd69738fc1aa286ee30e53ed7049d64d672ca1994008e71"
|
|
1065
1065
|
},
|
|
1066
1066
|
{
|
|
1067
1067
|
"alg": "SHA3-512",
|
|
1068
|
-
"content": "
|
|
1068
|
+
"content": "f310033529ffa980515daa40c155b309a56263a05214723df5567db709e22372a5caa772ba1ff0a4cd4e4ff1e398ecf4f81f15c186729fbe7c3d0e123ba16be9"
|
|
1069
1069
|
}
|
|
1070
1070
|
]
|
|
1071
1071
|
},
|
|
@@ -1661,11 +1661,11 @@
|
|
|
1661
1661
|
"hashes": [
|
|
1662
1662
|
{
|
|
1663
1663
|
"alg": "SHA-256",
|
|
1664
|
-
"content": "
|
|
1664
|
+
"content": "188c660ebfd03913aafe0a2d8fc7975081b6a1c786eb0201338e62985b2f51c7"
|
|
1665
1665
|
},
|
|
1666
1666
|
{
|
|
1667
1667
|
"alg": "SHA3-512",
|
|
1668
|
-
"content": "
|
|
1668
|
+
"content": "7e656d60bdf6fa0eb35ca9925fb04c04b5e1658f860ee1c8ab561e03c889c85d55a6aabefb8639207f24b6d8f170230e353b2eb5efbbe9f00927f146197c0692"
|
|
1669
1669
|
}
|
|
1670
1670
|
]
|
|
1671
1671
|
},
|