@blamejs/exceptd-skills 0.13.0 → 0.13.1
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 +33 -0
- package/data/_indexes/_meta.json +9 -9
- package/data/_indexes/activity-feed.json +2 -2
- package/data/_indexes/catalog-summaries.json +2 -2
- package/data/_indexes/chains.json +494 -10
- package/data/atlas-ttps.json +1 -0
- package/data/attack-techniques.json +13 -4
- package/data/cve-catalog.json +177 -3
- package/data/cwe-catalog.json +7 -3
- package/data/framework-control-gaps.json +19 -7
- package/data/zeroday-lessons.json +178 -0
- package/lib/refresh-external.js +7 -0
- package/lib/source-advisories.js +281 -0
- package/manifest.json +44 -44
- package/orchestrator/index.js +175 -0
- package/package.json +1 -1
- package/sbom.cdx.json +29 -18
package/orchestrator/index.js
CHANGED
|
@@ -1085,9 +1085,20 @@ function runWatchlist(rawArgs = []) {
|
|
|
1085
1085
|
const { parseFrontmatter, extractFrontmatterBlock } = require('../lib/lint-skills.js');
|
|
1086
1086
|
|
|
1087
1087
|
const byskill = rawArgs.includes('--by-skill');
|
|
1088
|
+
const alertsMode = rawArgs.includes('--alerts');
|
|
1088
1089
|
const manifestPath = path.join(__dirname, '..', 'manifest.json');
|
|
1089
1090
|
const repoRoot = path.join(__dirname, '..');
|
|
1090
1091
|
|
|
1092
|
+
// v0.13.1: --alerts re-scopes watchlist from "skills forward_watch" to
|
|
1093
|
+
// "CVE-class alert patterns" — surfaces catalog entries matching
|
|
1094
|
+
// high-priority shape rules (kernel-LPE-with-PoC, supply-chain-family,
|
|
1095
|
+
// AI-discovered-KEV, recently-disclosed-with-active-exploitation).
|
|
1096
|
+
// The two modes are mutually exclusive; --alerts short-circuits the
|
|
1097
|
+
// forward-watch aggregation.
|
|
1098
|
+
if (alertsMode) {
|
|
1099
|
+
return runWatchlistAlerts(rawArgs);
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1091
1102
|
let manifest;
|
|
1092
1103
|
try {
|
|
1093
1104
|
manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
@@ -1200,6 +1211,170 @@ function runWatchlist(rawArgs = []) {
|
|
|
1200
1211
|
console.log(`Run with --by-skill to invert the view.`);
|
|
1201
1212
|
}
|
|
1202
1213
|
|
|
1214
|
+
/**
|
|
1215
|
+
* v0.13.1 — runWatchlistAlerts surfaces CVE catalog entries matching
|
|
1216
|
+
* high-priority pattern rules. Closes the post-mortem gap from
|
|
1217
|
+
* CVE-2026-46333 (ssh-keysign-pwn) where the toolkit shipped a CVE
|
|
1218
|
+
* matching the kernel-LPE-with-public-PoC shape but had no programmatic
|
|
1219
|
+
* way for an operator to ask "what just landed that needs attention?".
|
|
1220
|
+
*
|
|
1221
|
+
* Patterns are evaluated against every catalog entry; multiple patterns
|
|
1222
|
+
* may fire on the same entry (the report carries the list). The age
|
|
1223
|
+
* filter — pattern.fresh_days — bounds the "recently disclosed" patterns;
|
|
1224
|
+
* older entries already had attention.
|
|
1225
|
+
*
|
|
1226
|
+
* Output (JSON mode):
|
|
1227
|
+
* {
|
|
1228
|
+
* ok: true,
|
|
1229
|
+
* verb: "watchlist",
|
|
1230
|
+
* mode: "alerts",
|
|
1231
|
+
* generated_at: "...",
|
|
1232
|
+
* patterns_evaluated: 5,
|
|
1233
|
+
* entries_scanned: 39,
|
|
1234
|
+
* alerts: [
|
|
1235
|
+
* { cve_id, name, rwep_score, patterns: ["kernel_lpe_class", ...],
|
|
1236
|
+
* disclosed: "...", source_verified: "...", links: [...] }
|
|
1237
|
+
* ]
|
|
1238
|
+
* }
|
|
1239
|
+
*/
|
|
1240
|
+
function runWatchlistAlerts(rawArgs = []) {
|
|
1241
|
+
const fs = require('fs');
|
|
1242
|
+
const path = require('path');
|
|
1243
|
+
const jsonOut = rawArgs.includes('--json');
|
|
1244
|
+
const cvePath = path.join(__dirname, '..', 'data', 'cve-catalog.json');
|
|
1245
|
+
let catalog;
|
|
1246
|
+
try {
|
|
1247
|
+
catalog = JSON.parse(fs.readFileSync(cvePath, 'utf8'));
|
|
1248
|
+
} catch (err) {
|
|
1249
|
+
console.error(`[watchlist --alerts] cannot read ${cvePath}: ${err.message}`);
|
|
1250
|
+
safeExit(EXIT_CODES.GENERIC_FAILURE);
|
|
1251
|
+
return;
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
// Pattern definitions. Each pattern is a predicate against a single
|
|
1255
|
+
// catalog entry plus a label + severity. Patterns are intentionally
|
|
1256
|
+
// narrow — false-positive flood would defeat the alert purpose.
|
|
1257
|
+
const today = new Date();
|
|
1258
|
+
function daysSince(iso) {
|
|
1259
|
+
if (typeof iso !== 'string') return Infinity;
|
|
1260
|
+
const t = Date.parse(iso + 'T00:00:00Z');
|
|
1261
|
+
if (Number.isNaN(t)) return Infinity;
|
|
1262
|
+
return Math.floor((today - t) / (24 * 60 * 60 * 1000));
|
|
1263
|
+
}
|
|
1264
|
+
const PATTERNS = [
|
|
1265
|
+
{
|
|
1266
|
+
id: 'kernel_lpe_with_poc',
|
|
1267
|
+
severity: 'high',
|
|
1268
|
+
description: 'Linux kernel LPE class with public PoC. The CVE-2026-46333 (ssh-keysign-pwn) / CVE-2026-46300 (Fragnesia) / CVE-2026-31431 (Copy Fail) shape.',
|
|
1269
|
+
match: (e) =>
|
|
1270
|
+
e && typeof e.vector === 'string' &&
|
|
1271
|
+
/kernel|linux|ptrace|pidfd/i.test(`${e.name || ''} ${e.vector}`) &&
|
|
1272
|
+
e.poc_available === true &&
|
|
1273
|
+
(e.rwep_factors?.blast_radius || 0) >= 25,
|
|
1274
|
+
},
|
|
1275
|
+
{
|
|
1276
|
+
id: 'supply_chain_family',
|
|
1277
|
+
severity: 'high',
|
|
1278
|
+
description: 'Malicious package or framework family (npm / PyPI registry-pivot). The MAL- entries + Shai-Hulud class.',
|
|
1279
|
+
match: (e, id) =>
|
|
1280
|
+
id.startsWith('MAL-') ||
|
|
1281
|
+
(typeof e?.type === 'string' && /malicious|supply.chain|registry-pivot/i.test(e.type)),
|
|
1282
|
+
},
|
|
1283
|
+
{
|
|
1284
|
+
id: 'ai_discovered_kev',
|
|
1285
|
+
severity: 'high',
|
|
1286
|
+
description: 'AI-discovered CVE that also appears on CISA KEV — the operational-reality intersection Hard Rule #7 calls out.',
|
|
1287
|
+
match: (e) => e?.ai_discovered === true && e?.cisa_kev === true,
|
|
1288
|
+
},
|
|
1289
|
+
{
|
|
1290
|
+
id: 'active_exploitation_unpatched',
|
|
1291
|
+
severity: 'critical',
|
|
1292
|
+
description: 'Confirmed in-the-wild exploitation AND no patch available. Defensive-posture-only window.',
|
|
1293
|
+
match: (e) => e?.active_exploitation === 'confirmed' && e?.patch_available !== true,
|
|
1294
|
+
},
|
|
1295
|
+
{
|
|
1296
|
+
id: 'recent_poc_no_kev_yet',
|
|
1297
|
+
severity: 'medium',
|
|
1298
|
+
description: 'CVE with public PoC verified within the last 14 days but not yet on KEV. The "exploitation expected; KEV catch-up pending" window.',
|
|
1299
|
+
match: (e) =>
|
|
1300
|
+
e?.poc_available === true &&
|
|
1301
|
+
e?.cisa_kev !== true &&
|
|
1302
|
+
daysSince(e?.source_verified) <= 14,
|
|
1303
|
+
fresh_only: true,
|
|
1304
|
+
},
|
|
1305
|
+
];
|
|
1306
|
+
|
|
1307
|
+
const alerts = [];
|
|
1308
|
+
let scanned = 0;
|
|
1309
|
+
for (const [id, entry] of Object.entries(catalog)) {
|
|
1310
|
+
if (id === '_meta') continue;
|
|
1311
|
+
if (!entry || typeof entry !== 'object') continue;
|
|
1312
|
+
scanned++;
|
|
1313
|
+
const matched = [];
|
|
1314
|
+
for (const p of PATTERNS) {
|
|
1315
|
+
try {
|
|
1316
|
+
if (p.match(entry, id)) matched.push({ id: p.id, severity: p.severity });
|
|
1317
|
+
} catch { /* defensive: pattern matcher must not throw on malformed entries */ }
|
|
1318
|
+
}
|
|
1319
|
+
if (matched.length === 0) continue;
|
|
1320
|
+
alerts.push({
|
|
1321
|
+
cve_id: id,
|
|
1322
|
+
name: entry.name || null,
|
|
1323
|
+
rwep_score: entry.rwep_score ?? null,
|
|
1324
|
+
cisa_kev: entry.cisa_kev ?? null,
|
|
1325
|
+
poc_available: entry.poc_available ?? null,
|
|
1326
|
+
active_exploitation: entry.active_exploitation ?? null,
|
|
1327
|
+
patch_available: entry.patch_available ?? null,
|
|
1328
|
+
source_verified: entry.source_verified || null,
|
|
1329
|
+
patterns: matched,
|
|
1330
|
+
links: Array.isArray(entry.verification_sources) ? entry.verification_sources.slice(0, 3) : [],
|
|
1331
|
+
});
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
// Sort: critical-severity matches first, then high, then medium; within
|
|
1335
|
+
// each band, highest RWEP first; finally CVE-id ascending for stability.
|
|
1336
|
+
const severityWeight = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
1337
|
+
alerts.sort((a, b) => {
|
|
1338
|
+
const sa = Math.min(...a.patterns.map((p) => severityWeight[p.severity] ?? 9));
|
|
1339
|
+
const sb = Math.min(...b.patterns.map((p) => severityWeight[p.severity] ?? 9));
|
|
1340
|
+
if (sa !== sb) return sa - sb;
|
|
1341
|
+
const ra = a.rwep_score ?? -1;
|
|
1342
|
+
const rb = b.rwep_score ?? -1;
|
|
1343
|
+
if (ra !== rb) return rb - ra;
|
|
1344
|
+
return a.cve_id.localeCompare(b.cve_id);
|
|
1345
|
+
});
|
|
1346
|
+
|
|
1347
|
+
if (jsonOut) {
|
|
1348
|
+
process.stdout.write(JSON.stringify({
|
|
1349
|
+
ok: true,
|
|
1350
|
+
verb: 'watchlist',
|
|
1351
|
+
mode: 'alerts',
|
|
1352
|
+
generated_at: today.toISOString(),
|
|
1353
|
+
patterns_evaluated: PATTERNS.length,
|
|
1354
|
+
entries_scanned: scanned,
|
|
1355
|
+
alert_count: alerts.length,
|
|
1356
|
+
alerts,
|
|
1357
|
+
}) + '\n');
|
|
1358
|
+
return;
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
console.log(`\nCVE-class Alerts — ${today.toISOString()}`);
|
|
1362
|
+
console.log(`Entries scanned: ${scanned} patterns evaluated: ${PATTERNS.length} alerts: ${alerts.length}\n`);
|
|
1363
|
+
if (alerts.length === 0) {
|
|
1364
|
+
console.log('No alert-pattern matches in current catalog.');
|
|
1365
|
+
return;
|
|
1366
|
+
}
|
|
1367
|
+
for (const a of alerts) {
|
|
1368
|
+
const labels = a.patterns.map((p) => `[${p.severity}] ${p.id}`).join(', ');
|
|
1369
|
+
console.log(`${a.cve_id} RWEP=${a.rwep_score ?? '?'} KEV=${a.cisa_kev ? 'Y' : 'N'} PoC=${a.poc_available ? 'Y' : 'N'} patch=${a.patch_available ? 'Y' : 'N'} active=${a.active_exploitation ?? '?'}`);
|
|
1370
|
+
console.log(` ${a.name || '(no name)'}`);
|
|
1371
|
+
console.log(` patterns: ${labels}`);
|
|
1372
|
+
if (a.links.length > 0) console.log(` ${a.links[0]}`);
|
|
1373
|
+
console.log('');
|
|
1374
|
+
}
|
|
1375
|
+
console.log('Run with --json to consume programmatically.');
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1203
1378
|
/**
|
|
1204
1379
|
* Cache-first variant of validateAllCves. For each catalog CVE, reads the
|
|
1205
1380
|
* NVD + EPSS payload from the prefetch cache (cacheDir/nvd/<id>.json +
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blamejs/exceptd-skills",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.1",
|
|
4
4
|
"description": "AI security skills grounded in mid-2026 threat reality, not stale framework documentation. 42 skills, 10 catalogs, 34 jurisdictions, pre-computed indexes, 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:c9932465-eaaf-45d0-850b-1ac483acd405",
|
|
5
5
|
"version": 1,
|
|
6
6
|
"metadata": {
|
|
7
|
-
"timestamp": "
|
|
7
|
+
"timestamp": "2133-03-02T22:32:05.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.1"
|
|
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.1",
|
|
17
17
|
"type": "application",
|
|
18
18
|
"name": "@blamejs/exceptd-skills",
|
|
19
|
-
"version": "0.13.
|
|
19
|
+
"version": "0.13.1",
|
|
20
20
|
"description": "AI security skills grounded in mid-2026 threat reality, not stale framework documentation. 42 skills, 10 catalogs, 34 jurisdictions, pre-computed indexes, 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.1",
|
|
29
29
|
"hashes": [
|
|
30
30
|
{
|
|
31
31
|
"alg": "SHA-256",
|
|
32
|
-
"content": "
|
|
32
|
+
"content": "4b9469db507f7f20a000a34c40f90adbbc98c328f2fc7ddee22843732a024c09"
|
|
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.1"
|
|
39
39
|
},
|
|
40
40
|
{
|
|
41
41
|
"type": "vcs",
|
|
@@ -108,7 +108,7 @@
|
|
|
108
108
|
"hashes": [
|
|
109
109
|
{
|
|
110
110
|
"alg": "SHA-256",
|
|
111
|
-
"content": "
|
|
111
|
+
"content": "27fbbfa0da04040c626789c887d0ea570d865bcb9e99ea6ef3fd670c73a39b5b"
|
|
112
112
|
}
|
|
113
113
|
]
|
|
114
114
|
},
|
|
@@ -240,7 +240,7 @@
|
|
|
240
240
|
"hashes": [
|
|
241
241
|
{
|
|
242
242
|
"alg": "SHA-256",
|
|
243
|
-
"content": "
|
|
243
|
+
"content": "0ec427652a9e613f04675beb26dc4c08934ba291e47427972b2a008c151cca78"
|
|
244
244
|
}
|
|
245
245
|
]
|
|
246
246
|
},
|
|
@@ -251,7 +251,7 @@
|
|
|
251
251
|
"hashes": [
|
|
252
252
|
{
|
|
253
253
|
"alg": "SHA-256",
|
|
254
|
-
"content": "
|
|
254
|
+
"content": "0ca33f8b0cf55a43de1290e310096020c4e0d16305bd01bcbe6cb46e0278caa8"
|
|
255
255
|
}
|
|
256
256
|
]
|
|
257
257
|
},
|
|
@@ -262,7 +262,7 @@
|
|
|
262
262
|
"hashes": [
|
|
263
263
|
{
|
|
264
264
|
"alg": "SHA-256",
|
|
265
|
-
"content": "
|
|
265
|
+
"content": "7fae34cf0abbd09abbbbd6a61ea06e487ddbd57060d3af6a58528c684156cf60"
|
|
266
266
|
}
|
|
267
267
|
]
|
|
268
268
|
},
|
|
@@ -273,7 +273,7 @@
|
|
|
273
273
|
"hashes": [
|
|
274
274
|
{
|
|
275
275
|
"alg": "SHA-256",
|
|
276
|
-
"content": "
|
|
276
|
+
"content": "832d096bd52081fe43c082fd6958f9054d6b6e136df5b3d4cef7efd0ea49a843"
|
|
277
277
|
}
|
|
278
278
|
]
|
|
279
279
|
},
|
|
@@ -317,7 +317,7 @@
|
|
|
317
317
|
"hashes": [
|
|
318
318
|
{
|
|
319
319
|
"alg": "SHA-256",
|
|
320
|
-
"content": "
|
|
320
|
+
"content": "5e2baf1e435c5b61b183e3f603636eae4fab34ee800488919c679665882c4f62"
|
|
321
321
|
}
|
|
322
322
|
]
|
|
323
323
|
},
|
|
@@ -570,7 +570,7 @@
|
|
|
570
570
|
"hashes": [
|
|
571
571
|
{
|
|
572
572
|
"alg": "SHA-256",
|
|
573
|
-
"content": "
|
|
573
|
+
"content": "40d666d0932da24b425b01ced0f9c9e5f2e6cfd2082f53861d982919dde56a4a"
|
|
574
574
|
}
|
|
575
575
|
]
|
|
576
576
|
},
|
|
@@ -724,7 +724,7 @@
|
|
|
724
724
|
"hashes": [
|
|
725
725
|
{
|
|
726
726
|
"alg": "SHA-256",
|
|
727
|
-
"content": "
|
|
727
|
+
"content": "3624e86150e85a33cb79d62193091fc1409085c3600f222dd65b2aa09ef728a8"
|
|
728
728
|
}
|
|
729
729
|
]
|
|
730
730
|
},
|
|
@@ -805,6 +805,17 @@
|
|
|
805
805
|
}
|
|
806
806
|
]
|
|
807
807
|
},
|
|
808
|
+
{
|
|
809
|
+
"bom-ref": "file:lib/source-advisories.js",
|
|
810
|
+
"type": "file",
|
|
811
|
+
"name": "lib/source-advisories.js",
|
|
812
|
+
"hashes": [
|
|
813
|
+
{
|
|
814
|
+
"alg": "SHA-256",
|
|
815
|
+
"content": "678cce9841ee92128e777cc0f355e020bd69c37cbd637be91479858e6a4958fd"
|
|
816
|
+
}
|
|
817
|
+
]
|
|
818
|
+
},
|
|
808
819
|
{
|
|
809
820
|
"bom-ref": "file:lib/source-ghsa.js",
|
|
810
821
|
"type": "file",
|
|
@@ -977,7 +988,7 @@
|
|
|
977
988
|
"hashes": [
|
|
978
989
|
{
|
|
979
990
|
"alg": "SHA-256",
|
|
980
|
-
"content": "
|
|
991
|
+
"content": "4535de4e48530ccb3c5d97402ae9dcf45f0336b838bddb8ab081c6df9632014a"
|
|
981
992
|
}
|
|
982
993
|
]
|
|
983
994
|
},
|
|
@@ -1021,7 +1032,7 @@
|
|
|
1021
1032
|
"hashes": [
|
|
1022
1033
|
{
|
|
1023
1034
|
"alg": "SHA-256",
|
|
1024
|
-
"content": "
|
|
1035
|
+
"content": "7c7378f69024b1abb11d2f17978f9023b262ac6a67a82c2eb31d4996c2caee28"
|
|
1025
1036
|
}
|
|
1026
1037
|
]
|
|
1027
1038
|
},
|