@blamejs/exceptd-skills 0.9.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/AGENTS.md +232 -0
- package/ARCHITECTURE.md +267 -0
- package/CHANGELOG.md +616 -0
- package/CONTEXT.md +203 -0
- package/LICENSE +200 -0
- package/NOTICE +82 -0
- package/README.md +307 -0
- package/SECURITY.md +73 -0
- package/agents/README.md +81 -0
- package/agents/report-generator.md +156 -0
- package/agents/skill-updater.md +102 -0
- package/agents/source-validator.md +119 -0
- package/agents/threat-researcher.md +149 -0
- package/bin/exceptd.js +183 -0
- package/data/_indexes/_meta.json +88 -0
- package/data/_indexes/activity-feed.json +362 -0
- package/data/_indexes/catalog-summaries.json +229 -0
- package/data/_indexes/chains.json +7135 -0
- package/data/_indexes/currency.json +359 -0
- package/data/_indexes/did-ladders.json +451 -0
- package/data/_indexes/frequency.json +2072 -0
- package/data/_indexes/handoff-dag.json +476 -0
- package/data/_indexes/jurisdiction-clocks.json +967 -0
- package/data/_indexes/jurisdiction-map.json +536 -0
- package/data/_indexes/recipes.json +319 -0
- package/data/_indexes/section-offsets.json +3656 -0
- package/data/_indexes/stale-content.json +14 -0
- package/data/_indexes/summary-cards.json +1736 -0
- package/data/_indexes/theater-fingerprints.json +381 -0
- package/data/_indexes/token-budget.json +2137 -0
- package/data/_indexes/trigger-table.json +1374 -0
- package/data/_indexes/xref.json +818 -0
- package/data/atlas-ttps.json +282 -0
- package/data/cve-catalog.json +496 -0
- package/data/cwe-catalog.json +1017 -0
- package/data/d3fend-catalog.json +738 -0
- package/data/dlp-controls.json +1039 -0
- package/data/exploit-availability.json +67 -0
- package/data/framework-control-gaps.json +1255 -0
- package/data/global-frameworks.json +2913 -0
- package/data/rfc-references.json +324 -0
- package/data/zeroday-lessons.json +377 -0
- package/keys/public.pem +3 -0
- package/lib/framework-gap.js +328 -0
- package/lib/job-queue.js +195 -0
- package/lib/lint-skills.js +536 -0
- package/lib/prefetch.js +372 -0
- package/lib/refresh-external.js +713 -0
- package/lib/schemas/cve-catalog.schema.json +151 -0
- package/lib/schemas/manifest.schema.json +106 -0
- package/lib/schemas/skill-frontmatter.schema.json +113 -0
- package/lib/scoring.js +149 -0
- package/lib/sign.js +197 -0
- package/lib/ttp-mapper.js +80 -0
- package/lib/validate-catalog-meta.js +198 -0
- package/lib/validate-cve-catalog.js +213 -0
- package/lib/validate-indexes.js +83 -0
- package/lib/validate-package.js +162 -0
- package/lib/validate-vendor.js +85 -0
- package/lib/verify.js +216 -0
- package/lib/worker-pool.js +84 -0
- package/manifest-snapshot.json +1833 -0
- package/manifest.json +2108 -0
- package/orchestrator/README.md +124 -0
- package/orchestrator/dispatcher.js +140 -0
- package/orchestrator/event-bus.js +146 -0
- package/orchestrator/index.js +874 -0
- package/orchestrator/pipeline.js +201 -0
- package/orchestrator/scanner.js +327 -0
- package/orchestrator/scheduler.js +137 -0
- package/package.json +113 -0
- package/sbom.cdx.json +158 -0
- package/scripts/audit-cross-skill.js +261 -0
- package/scripts/audit-perf.js +160 -0
- package/scripts/bootstrap.js +205 -0
- package/scripts/build-indexes.js +721 -0
- package/scripts/builders/activity-feed.js +79 -0
- package/scripts/builders/catalog-summaries.js +67 -0
- package/scripts/builders/currency.js +109 -0
- package/scripts/builders/cwe-chains.js +105 -0
- package/scripts/builders/did-ladders.js +149 -0
- package/scripts/builders/frequency.js +89 -0
- package/scripts/builders/jurisdiction-clocks.js +126 -0
- package/scripts/builders/recipes.js +159 -0
- package/scripts/builders/section-offsets.js +162 -0
- package/scripts/builders/stale-content.js +171 -0
- package/scripts/builders/summary-cards.js +166 -0
- package/scripts/builders/theater-fingerprints.js +198 -0
- package/scripts/builders/token-budget.js +96 -0
- package/scripts/check-manifest-snapshot.js +217 -0
- package/scripts/predeploy.js +267 -0
- package/scripts/refresh-manifest-snapshot.js +57 -0
- package/scripts/refresh-sbom.js +222 -0
- package/skills/age-gates-child-safety/skill.md +456 -0
- package/skills/ai-attack-surface/skill.md +282 -0
- package/skills/ai-c2-detection/skill.md +440 -0
- package/skills/ai-risk-management/skill.md +311 -0
- package/skills/api-security/skill.md +287 -0
- package/skills/attack-surface-pentest/skill.md +381 -0
- package/skills/cloud-security/skill.md +384 -0
- package/skills/compliance-theater/skill.md +365 -0
- package/skills/container-runtime-security/skill.md +379 -0
- package/skills/coordinated-vuln-disclosure/skill.md +473 -0
- package/skills/defensive-countermeasure-mapping/skill.md +300 -0
- package/skills/dlp-gap-analysis/skill.md +337 -0
- package/skills/email-security-anti-phishing/skill.md +206 -0
- package/skills/exploit-scoring/skill.md +331 -0
- package/skills/framework-gap-analysis/skill.md +374 -0
- package/skills/fuzz-testing-strategy/skill.md +313 -0
- package/skills/global-grc/skill.md +564 -0
- package/skills/identity-assurance/skill.md +272 -0
- package/skills/incident-response-playbook/skill.md +546 -0
- package/skills/kernel-lpe-triage/skill.md +303 -0
- package/skills/mcp-agent-trust/skill.md +326 -0
- package/skills/mlops-security/skill.md +325 -0
- package/skills/ot-ics-security/skill.md +340 -0
- package/skills/policy-exception-gen/skill.md +437 -0
- package/skills/pqc-first/skill.md +546 -0
- package/skills/rag-pipeline-security/skill.md +294 -0
- package/skills/researcher/skill.md +310 -0
- package/skills/sector-energy/skill.md +409 -0
- package/skills/sector-federal-government/skill.md +302 -0
- package/skills/sector-financial/skill.md +398 -0
- package/skills/sector-healthcare/skill.md +373 -0
- package/skills/security-maturity-tiers/skill.md +464 -0
- package/skills/skill-update-loop/skill.md +463 -0
- package/skills/supply-chain-integrity/skill.md +318 -0
- package/skills/threat-model-currency/skill.md +404 -0
- package/skills/threat-modeling-methodology/skill.md +312 -0
- package/skills/webapp-security/skill.md +281 -0
- package/skills/zeroday-gap-learn/skill.md +350 -0
- package/vendor/blamejs/LICENSE +201 -0
- package/vendor/blamejs/README.md +54 -0
- package/vendor/blamejs/_PROVENANCE.json +54 -0
- package/vendor/blamejs/retry.js +335 -0
- package/vendor/blamejs/worker-pool.js +418 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://exceptd.com/schemas/cve-catalog.schema.json",
|
|
4
|
+
"title": "exceptd CVE Catalog Entry",
|
|
5
|
+
"description": "Schema for a single CVE entry in data/cve-catalog.json. CVE keys (e.g. CVE-2026-31431) map to objects matching this schema. The reserved key _meta is not validated against this schema.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": true,
|
|
8
|
+
"required": [
|
|
9
|
+
"name",
|
|
10
|
+
"type",
|
|
11
|
+
"cvss_score",
|
|
12
|
+
"cvss_vector",
|
|
13
|
+
"cisa_kev",
|
|
14
|
+
"poc_available",
|
|
15
|
+
"ai_discovered",
|
|
16
|
+
"active_exploitation",
|
|
17
|
+
"affected",
|
|
18
|
+
"affected_versions",
|
|
19
|
+
"vector",
|
|
20
|
+
"patch_available",
|
|
21
|
+
"patch_required_reboot",
|
|
22
|
+
"live_patch_available",
|
|
23
|
+
"framework_control_gaps",
|
|
24
|
+
"atlas_refs",
|
|
25
|
+
"attack_refs",
|
|
26
|
+
"rwep_score",
|
|
27
|
+
"rwep_factors",
|
|
28
|
+
"source_verified",
|
|
29
|
+
"verification_sources",
|
|
30
|
+
"last_updated"
|
|
31
|
+
],
|
|
32
|
+
"properties": {
|
|
33
|
+
"name": {
|
|
34
|
+
"type": "string",
|
|
35
|
+
"minLength": 1,
|
|
36
|
+
"description": "Human-readable vulnerability name (e.g. 'Copy Fail')."
|
|
37
|
+
},
|
|
38
|
+
"type": {
|
|
39
|
+
"type": "string",
|
|
40
|
+
"minLength": 1,
|
|
41
|
+
"description": "Vulnerability class (LPE, RCE-via-prompt-injection, RCE-supply-chain, etc.)."
|
|
42
|
+
},
|
|
43
|
+
"cvss_score": {
|
|
44
|
+
"type": "number",
|
|
45
|
+
"minimum": 0.0,
|
|
46
|
+
"maximum": 10.0
|
|
47
|
+
},
|
|
48
|
+
"cvss_vector": {
|
|
49
|
+
"type": "string",
|
|
50
|
+
"pattern": "^CVSS:[0-9]+(\\.[0-9]+)?/"
|
|
51
|
+
},
|
|
52
|
+
"cisa_kev": { "type": "boolean" },
|
|
53
|
+
"cisa_kev_date": {
|
|
54
|
+
"type": ["string", "null"],
|
|
55
|
+
"description": "ISO date string when added to CISA KEV, or null."
|
|
56
|
+
},
|
|
57
|
+
"cisa_kev_due_date": {
|
|
58
|
+
"type": ["string", "null"]
|
|
59
|
+
},
|
|
60
|
+
"poc_available": { "type": "boolean" },
|
|
61
|
+
"poc_description": { "type": "string" },
|
|
62
|
+
"ai_discovered": {
|
|
63
|
+
"description": "Whether the vulnerability was discovered with AI assistance.",
|
|
64
|
+
"type": ["boolean", "string"]
|
|
65
|
+
},
|
|
66
|
+
"ai_discovery_notes": { "type": "string" },
|
|
67
|
+
"ai_assisted_weaponization": { "type": "boolean" },
|
|
68
|
+
"ai_assisted_notes": { "type": "string" },
|
|
69
|
+
"active_exploitation": {
|
|
70
|
+
"type": "string",
|
|
71
|
+
"enum": ["confirmed", "suspected", "none", "unknown"]
|
|
72
|
+
},
|
|
73
|
+
"affected": {
|
|
74
|
+
"type": "string",
|
|
75
|
+
"minLength": 1,
|
|
76
|
+
"description": "Free-form description of affected products/versions."
|
|
77
|
+
},
|
|
78
|
+
"affected_versions": {
|
|
79
|
+
"type": "array",
|
|
80
|
+
"items": { "type": "string" },
|
|
81
|
+
"minItems": 1
|
|
82
|
+
},
|
|
83
|
+
"vector": { "type": "string", "minLength": 1 },
|
|
84
|
+
"complexity": { "type": "string" },
|
|
85
|
+
"complexity_notes": { "type": "string" },
|
|
86
|
+
"patch_available": { "type": "boolean" },
|
|
87
|
+
"patch_required_reboot": { "type": "boolean" },
|
|
88
|
+
"live_patch_available": { "type": "boolean" },
|
|
89
|
+
"live_patch_tools": {
|
|
90
|
+
"type": "array",
|
|
91
|
+
"items": { "type": "string" }
|
|
92
|
+
},
|
|
93
|
+
"live_patch_notes": { "type": "string" },
|
|
94
|
+
"framework_control_gaps": {
|
|
95
|
+
"type": "object",
|
|
96
|
+
"minProperties": 1,
|
|
97
|
+
"description": "Map of framework control ID (or ALL-MAJOR-FRAMEWORKS) to gap statement. Per AGENTS.md rule #4, no orphaned controls.",
|
|
98
|
+
"additionalProperties": { "type": "string" }
|
|
99
|
+
},
|
|
100
|
+
"atlas_refs": {
|
|
101
|
+
"type": "array",
|
|
102
|
+
"items": { "type": "string", "pattern": "^AML\\.T[0-9]{4}(\\.[0-9]{3})?$" }
|
|
103
|
+
},
|
|
104
|
+
"attack_refs": {
|
|
105
|
+
"type": "array",
|
|
106
|
+
"items": { "type": "string", "pattern": "^T[0-9]{4}(\\.[0-9]{3})?$" }
|
|
107
|
+
},
|
|
108
|
+
"rwep_score": {
|
|
109
|
+
"type": "number",
|
|
110
|
+
"minimum": 0,
|
|
111
|
+
"maximum": 100
|
|
112
|
+
},
|
|
113
|
+
"rwep_factors": {
|
|
114
|
+
"type": "object",
|
|
115
|
+
"required": [
|
|
116
|
+
"cisa_kev",
|
|
117
|
+
"poc_available",
|
|
118
|
+
"ai_factor",
|
|
119
|
+
"active_exploitation",
|
|
120
|
+
"blast_radius",
|
|
121
|
+
"patch_available",
|
|
122
|
+
"live_patch_available",
|
|
123
|
+
"reboot_required"
|
|
124
|
+
],
|
|
125
|
+
"properties": {
|
|
126
|
+
"cisa_kev": { "type": "number" },
|
|
127
|
+
"poc_available": { "type": "number" },
|
|
128
|
+
"ai_factor": { "type": "number" },
|
|
129
|
+
"active_exploitation": { "type": "number" },
|
|
130
|
+
"blast_radius": { "type": "number" },
|
|
131
|
+
"patch_available": { "type": "number" },
|
|
132
|
+
"live_patch_available": { "type": "number" },
|
|
133
|
+
"reboot_required": { "type": "number" }
|
|
134
|
+
},
|
|
135
|
+
"additionalProperties": true
|
|
136
|
+
},
|
|
137
|
+
"source_verified": {
|
|
138
|
+
"type": "string",
|
|
139
|
+
"pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$"
|
|
140
|
+
},
|
|
141
|
+
"verification_sources": {
|
|
142
|
+
"type": "array",
|
|
143
|
+
"items": { "type": "string", "format": "uri" },
|
|
144
|
+
"minItems": 1
|
|
145
|
+
},
|
|
146
|
+
"last_updated": {
|
|
147
|
+
"type": "string",
|
|
148
|
+
"pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$"
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://exceptd.com/schemas/manifest.schema.json",
|
|
4
|
+
"title": "exceptd manifest.json",
|
|
5
|
+
"description": "Schema for the top-level manifest.json describing the exceptd skill collection.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": true,
|
|
8
|
+
"required": [
|
|
9
|
+
"name",
|
|
10
|
+
"version",
|
|
11
|
+
"description",
|
|
12
|
+
"atlas_version",
|
|
13
|
+
"threat_review_date",
|
|
14
|
+
"skills"
|
|
15
|
+
],
|
|
16
|
+
"properties": {
|
|
17
|
+
"name": { "type": "string", "minLength": 1 },
|
|
18
|
+
"version": { "type": "string", "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$" },
|
|
19
|
+
"description": { "type": "string", "minLength": 1 },
|
|
20
|
+
"homepage": { "type": "string", "format": "uri" },
|
|
21
|
+
"license": { "type": "string", "minLength": 1 },
|
|
22
|
+
"atlas_version": { "type": "string", "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$" },
|
|
23
|
+
"threat_review_date": { "type": "string", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$" },
|
|
24
|
+
"sources_dir": { "type": "string" },
|
|
25
|
+
"agents_dir": { "type": "string" },
|
|
26
|
+
"reports_dir": { "type": "string" },
|
|
27
|
+
"skills": {
|
|
28
|
+
"type": "array",
|
|
29
|
+
"minItems": 1,
|
|
30
|
+
"items": { "$ref": "#/$defs/skillEntry" }
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"$defs": {
|
|
34
|
+
"skillEntry": {
|
|
35
|
+
"type": "object",
|
|
36
|
+
"additionalProperties": false,
|
|
37
|
+
"required": [
|
|
38
|
+
"name",
|
|
39
|
+
"version",
|
|
40
|
+
"path",
|
|
41
|
+
"description",
|
|
42
|
+
"triggers",
|
|
43
|
+
"data_deps",
|
|
44
|
+
"atlas_refs",
|
|
45
|
+
"attack_refs",
|
|
46
|
+
"framework_gaps",
|
|
47
|
+
"last_threat_review"
|
|
48
|
+
],
|
|
49
|
+
"properties": {
|
|
50
|
+
"name": {
|
|
51
|
+
"type": "string",
|
|
52
|
+
"pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$"
|
|
53
|
+
},
|
|
54
|
+
"version": { "type": "string", "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$" },
|
|
55
|
+
"path": {
|
|
56
|
+
"type": "string",
|
|
57
|
+
"pattern": "^skills/[a-z0-9][a-z0-9-]*[a-z0-9]/skill\\.md$"
|
|
58
|
+
},
|
|
59
|
+
"description": { "type": "string", "minLength": 10 },
|
|
60
|
+
"triggers": {
|
|
61
|
+
"type": "array",
|
|
62
|
+
"minItems": 1,
|
|
63
|
+
"items": { "type": "string", "minLength": 1 }
|
|
64
|
+
},
|
|
65
|
+
"data_deps": {
|
|
66
|
+
"type": "array",
|
|
67
|
+
"items": { "type": "string", "pattern": "^[A-Za-z0-9._-]+\\.json$" }
|
|
68
|
+
},
|
|
69
|
+
"atlas_refs": {
|
|
70
|
+
"type": "array",
|
|
71
|
+
"items": { "type": "string", "pattern": "^AML\\.T[0-9]{4}(\\.[0-9]{3})?$" }
|
|
72
|
+
},
|
|
73
|
+
"attack_refs": {
|
|
74
|
+
"type": "array",
|
|
75
|
+
"items": { "type": "string", "pattern": "^T[0-9]{4}(\\.[0-9]{3})?$" }
|
|
76
|
+
},
|
|
77
|
+
"framework_gaps": {
|
|
78
|
+
"type": "array",
|
|
79
|
+
"items": { "type": "string", "minLength": 1 }
|
|
80
|
+
},
|
|
81
|
+
"forward_watch": {
|
|
82
|
+
"type": "array",
|
|
83
|
+
"items": { "type": "string", "minLength": 1 }
|
|
84
|
+
},
|
|
85
|
+
"last_threat_review": {
|
|
86
|
+
"type": "string",
|
|
87
|
+
"pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$"
|
|
88
|
+
},
|
|
89
|
+
"sha256": {
|
|
90
|
+
"type": "string",
|
|
91
|
+
"pattern": "^[a-f0-9]{64}$",
|
|
92
|
+
"description": "Set by lib/verify.js when signing is not in use; replaced by signature when lib/sign.js runs."
|
|
93
|
+
},
|
|
94
|
+
"signature": {
|
|
95
|
+
"type": "string",
|
|
96
|
+
"description": "Ed25519 signature over skill.md content, base64-encoded. Added by lib/sign.js."
|
|
97
|
+
},
|
|
98
|
+
"signed_at": {
|
|
99
|
+
"type": "string",
|
|
100
|
+
"format": "date-time",
|
|
101
|
+
"description": "ISO 8601 timestamp written by lib/sign.js."
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://exceptd.com/schemas/skill-frontmatter.schema.json",
|
|
4
|
+
"title": "exceptd Skill Frontmatter",
|
|
5
|
+
"description": "Schema for the YAML frontmatter at the top of every skills/<name>/skill.md. Mirrors the spec in AGENTS.md (Skill File Format).",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": [
|
|
9
|
+
"name",
|
|
10
|
+
"version",
|
|
11
|
+
"description",
|
|
12
|
+
"triggers",
|
|
13
|
+
"data_deps",
|
|
14
|
+
"atlas_refs",
|
|
15
|
+
"attack_refs",
|
|
16
|
+
"framework_gaps",
|
|
17
|
+
"last_threat_review"
|
|
18
|
+
],
|
|
19
|
+
"properties": {
|
|
20
|
+
"name": {
|
|
21
|
+
"type": "string",
|
|
22
|
+
"pattern": "^[a-z0-9][a-z0-9-]*[a-z0-9]$",
|
|
23
|
+
"description": "Lowercase kebab-case identifier matching the directory under skills/."
|
|
24
|
+
},
|
|
25
|
+
"version": {
|
|
26
|
+
"type": "string",
|
|
27
|
+
"pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$",
|
|
28
|
+
"description": "Semantic version string. Quoted in YAML to preserve string type."
|
|
29
|
+
},
|
|
30
|
+
"description": {
|
|
31
|
+
"type": "string",
|
|
32
|
+
"minLength": 10,
|
|
33
|
+
"description": "One-line trigger description used by AI assistant skill matching."
|
|
34
|
+
},
|
|
35
|
+
"triggers": {
|
|
36
|
+
"type": "array",
|
|
37
|
+
"minItems": 1,
|
|
38
|
+
"items": { "type": "string", "minLength": 1 },
|
|
39
|
+
"description": "Phrase patterns that invoke the skill."
|
|
40
|
+
},
|
|
41
|
+
"data_deps": {
|
|
42
|
+
"type": "array",
|
|
43
|
+
"items": {
|
|
44
|
+
"type": "string",
|
|
45
|
+
"pattern": "^[A-Za-z0-9._-]+\\.json$"
|
|
46
|
+
},
|
|
47
|
+
"description": "Filenames (relative to data/) that this skill reads. Each must resolve to an existing file."
|
|
48
|
+
},
|
|
49
|
+
"atlas_refs": {
|
|
50
|
+
"type": "array",
|
|
51
|
+
"items": {
|
|
52
|
+
"type": "string",
|
|
53
|
+
"pattern": "^AML\\.T[0-9]{4}(\\.[0-9]{3})?$"
|
|
54
|
+
},
|
|
55
|
+
"description": "MITRE ATLAS TTP IDs at the pinned version (currently v5.1.0)."
|
|
56
|
+
},
|
|
57
|
+
"attack_refs": {
|
|
58
|
+
"type": "array",
|
|
59
|
+
"items": {
|
|
60
|
+
"type": "string",
|
|
61
|
+
"pattern": "^T[0-9]{4}(\\.[0-9]{3})?$"
|
|
62
|
+
},
|
|
63
|
+
"description": "MITRE ATT&CK technique IDs."
|
|
64
|
+
},
|
|
65
|
+
"framework_gaps": {
|
|
66
|
+
"type": "array",
|
|
67
|
+
"items": { "type": "string", "minLength": 1 },
|
|
68
|
+
"description": "Framework control IDs whose gap this skill addresses. Each must resolve in data/framework-control-gaps.json."
|
|
69
|
+
},
|
|
70
|
+
"rfc_refs": {
|
|
71
|
+
"type": "array",
|
|
72
|
+
"items": {
|
|
73
|
+
"type": "string",
|
|
74
|
+
"pattern": "^(RFC-[0-9]+|DRAFT-[A-Z0-9-]+)$"
|
|
75
|
+
},
|
|
76
|
+
"description": "Optional. IETF RFC numbers (e.g. RFC-8446) or Internet-Draft slugs (e.g. DRAFT-IETF-TLS-ECDHE-MLKEM) the skill depends on. Each must resolve in data/rfc-references.json."
|
|
77
|
+
},
|
|
78
|
+
"cwe_refs": {
|
|
79
|
+
"type": "array",
|
|
80
|
+
"items": {
|
|
81
|
+
"type": "string",
|
|
82
|
+
"pattern": "^CWE-[0-9]+$"
|
|
83
|
+
},
|
|
84
|
+
"description": "Optional. CWE (Common Weakness Enumeration) IDs the skill addresses as root-cause weakness classes. Each must resolve in data/cwe-catalog.json."
|
|
85
|
+
},
|
|
86
|
+
"d3fend_refs": {
|
|
87
|
+
"type": "array",
|
|
88
|
+
"items": {
|
|
89
|
+
"type": "string",
|
|
90
|
+
"pattern": "^D3-[A-Z]+$"
|
|
91
|
+
},
|
|
92
|
+
"description": "Optional. MITRE D3FEND defensive technique IDs the skill maps to. Each must resolve in data/d3fend-catalog.json."
|
|
93
|
+
},
|
|
94
|
+
"dlp_refs": {
|
|
95
|
+
"type": "array",
|
|
96
|
+
"items": {
|
|
97
|
+
"type": "string",
|
|
98
|
+
"pattern": "^DLP-[A-Z0-9-]+$"
|
|
99
|
+
},
|
|
100
|
+
"description": "Optional. DLP control IDs the skill addresses (channels, classifiers, surfaces, enforcement, evidence). Each must resolve in data/dlp-controls.json."
|
|
101
|
+
},
|
|
102
|
+
"forward_watch": {
|
|
103
|
+
"type": "array",
|
|
104
|
+
"items": { "type": "string", "minLength": 1 },
|
|
105
|
+
"description": "Optional. Upcoming standards changes or new TTPs to watch for skill update."
|
|
106
|
+
},
|
|
107
|
+
"last_threat_review": {
|
|
108
|
+
"type": "string",
|
|
109
|
+
"pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$",
|
|
110
|
+
"description": "ISO date of the last threat-intel review for this skill."
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
package/lib/scoring.js
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* RWEP — Real-World Exploit Priority scoring engine
|
|
5
|
+
* Supplements CVSS with exploit availability, active exploitation, and operational constraints.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const CVE_SCHEMA_REQUIRED = [
|
|
9
|
+
'type', 'cvss_score', 'cvss_vector', 'cisa_kev', 'poc_available',
|
|
10
|
+
'ai_discovered', 'active_exploitation', 'affected', 'patch_available',
|
|
11
|
+
'patch_required_reboot', 'live_patch_available', 'live_patch_tools',
|
|
12
|
+
'rwep_score', 'rwep_factors', 'atlas_refs', 'attack_refs',
|
|
13
|
+
'source_verified', 'verification_sources', 'last_updated'
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
// blast_radius range is 0-30; represents breadth of affected population.
|
|
17
|
+
// AI-discovered and AI-assisted-weaponization both contribute the ai_factor (+15).
|
|
18
|
+
// reboot_required applies whenever patch requires reboot, regardless of live-patch availability,
|
|
19
|
+
// because live-patch is a temporary workaround — full remediation window is extended.
|
|
20
|
+
const RWEP_WEIGHTS = {
|
|
21
|
+
cisa_kev: 25,
|
|
22
|
+
poc_available: 20,
|
|
23
|
+
ai_factor: 15,
|
|
24
|
+
active_exploitation: 20,
|
|
25
|
+
blast_radius: 30,
|
|
26
|
+
patch_available: -15,
|
|
27
|
+
live_patch_available:-10,
|
|
28
|
+
reboot_required: 5
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
function score(cveId, catalog) {
|
|
32
|
+
const entry = catalog[cveId];
|
|
33
|
+
if (!entry) throw new Error(`CVE not in catalog: ${cveId}`);
|
|
34
|
+
return entry.rwep_score;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function scoreCustom(factors) {
|
|
38
|
+
const {
|
|
39
|
+
cisa_kev = false,
|
|
40
|
+
poc_available = false,
|
|
41
|
+
ai_assisted_weapon = false,
|
|
42
|
+
ai_discovered = false,
|
|
43
|
+
active_exploitation = 'none',
|
|
44
|
+
blast_radius = 0,
|
|
45
|
+
patch_available = false,
|
|
46
|
+
live_patch_available = false,
|
|
47
|
+
reboot_required = false
|
|
48
|
+
} = factors;
|
|
49
|
+
|
|
50
|
+
let score = 0;
|
|
51
|
+
score += cisa_kev ? RWEP_WEIGHTS.cisa_kev : 0;
|
|
52
|
+
score += poc_available ? RWEP_WEIGHTS.poc_available : 0;
|
|
53
|
+
score += (ai_assisted_weapon || ai_discovered) ? RWEP_WEIGHTS.ai_factor : 0;
|
|
54
|
+
score += active_exploitation === 'confirmed' ? RWEP_WEIGHTS.active_exploitation : 0;
|
|
55
|
+
score += active_exploitation === 'suspected' ? Math.floor(RWEP_WEIGHTS.active_exploitation / 2) : 0;
|
|
56
|
+
score += Math.min(RWEP_WEIGHTS.blast_radius, blast_radius);
|
|
57
|
+
score += patch_available ? RWEP_WEIGHTS.patch_available : 0;
|
|
58
|
+
score += live_patch_available ? RWEP_WEIGHTS.live_patch_available : 0;
|
|
59
|
+
score += reboot_required ? RWEP_WEIGHTS.reboot_required : 0;
|
|
60
|
+
|
|
61
|
+
return Math.min(100, Math.max(0, score));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function timeline(rwepScore) {
|
|
65
|
+
if (rwepScore >= 90) return { hours: 4, label: 'Immediate — live patch or isolate within 4 hours' };
|
|
66
|
+
if (rwepScore >= 75) return { hours: 24, label: 'Urgent — patch or compensating controls within 24 hours' };
|
|
67
|
+
if (rwepScore >= 60) return { hours: 72, label: 'High — patch within 72 hours' };
|
|
68
|
+
if (rwepScore >= 40) return { hours: 168, label: 'Elevated — patch within 7 days' };
|
|
69
|
+
if (rwepScore >= 20) return { hours: 720, label: 'Standard — patch within 30 days' };
|
|
70
|
+
return { hours: null, label: 'Low — next scheduled maintenance' };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function compare(cveId, catalog) {
|
|
74
|
+
const entry = catalog[cveId];
|
|
75
|
+
if (!entry) throw new Error(`CVE not in catalog: ${cveId}`);
|
|
76
|
+
|
|
77
|
+
const rwep = entry.rwep_score;
|
|
78
|
+
const cvss = entry.cvss_score;
|
|
79
|
+
const cvssEquivalent = cvss * 10;
|
|
80
|
+
const delta = rwep - cvssEquivalent;
|
|
81
|
+
|
|
82
|
+
let explanation = '';
|
|
83
|
+
if (delta > 20) {
|
|
84
|
+
explanation = `RWEP significantly higher than CVSS equivalent. Factors driving delta: `;
|
|
85
|
+
const driving = [];
|
|
86
|
+
if (entry.cisa_kev) driving.push('CISA KEV (+25)');
|
|
87
|
+
if (entry.poc_available) driving.push('public PoC (+20)');
|
|
88
|
+
if (entry.ai_discovered) driving.push('AI-discovered (+15 weaponization)');
|
|
89
|
+
if (entry.active_exploitation === 'confirmed') driving.push('confirmed exploitation (+20)');
|
|
90
|
+
if (entry.patch_required_reboot && !entry.live_patch_available) driving.push('reboot required (+5)');
|
|
91
|
+
explanation += driving.join(', ');
|
|
92
|
+
explanation += '. Framework patch SLAs calibrated to CVSS are insufficient for this CVE.';
|
|
93
|
+
} else if (delta < -20) {
|
|
94
|
+
explanation = `RWEP lower than CVSS equivalent. Mitigating factors: `;
|
|
95
|
+
const mitigating = [];
|
|
96
|
+
if (entry.patch_available) mitigating.push('patch available (-15)');
|
|
97
|
+
if (entry.live_patch_available) mitigating.push('live patch available (-10)');
|
|
98
|
+
if (!entry.poc_available) mitigating.push('no public PoC');
|
|
99
|
+
if (!entry.cisa_kev) mitigating.push('not CISA KEV');
|
|
100
|
+
explanation += mitigating.join(', ');
|
|
101
|
+
} else {
|
|
102
|
+
explanation = 'CVSS and RWEP are broadly aligned for this CVE.';
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
cve_id: cveId,
|
|
107
|
+
cvss: cvss,
|
|
108
|
+
rwep: rwep,
|
|
109
|
+
cvss_framework_sla: timeline(cvssEquivalent),
|
|
110
|
+
rwep_actual_sla: timeline(rwep),
|
|
111
|
+
delta,
|
|
112
|
+
explanation
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function validate(catalog) {
|
|
117
|
+
const errors = [];
|
|
118
|
+
for (const [cveId, entry] of Object.entries(catalog)) {
|
|
119
|
+
if (cveId.startsWith('_')) continue;
|
|
120
|
+
for (const field of CVE_SCHEMA_REQUIRED) {
|
|
121
|
+
if (!(field in entry)) {
|
|
122
|
+
errors.push(`${cveId}: missing required field '${field}'`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (entry.poc_available && (!entry.poc_description || entry.poc_description.trim() === '')) {
|
|
126
|
+
errors.push(`${cveId}: poc_available=true but poc_description is empty`);
|
|
127
|
+
}
|
|
128
|
+
if (entry.live_patch_available && (!entry.live_patch_tools || entry.live_patch_tools.length === 0)) {
|
|
129
|
+
errors.push(`${cveId}: live_patch_available=true but live_patch_tools is empty`);
|
|
130
|
+
}
|
|
131
|
+
const calculatedRwep = scoreCustom({
|
|
132
|
+
cisa_kev: entry.cisa_kev,
|
|
133
|
+
poc_available: entry.poc_available,
|
|
134
|
+
ai_assisted_weapon: entry.ai_assisted_weaponization || false,
|
|
135
|
+
ai_discovered: entry.ai_discovered || false,
|
|
136
|
+
active_exploitation: entry.active_exploitation,
|
|
137
|
+
blast_radius: entry.rwep_factors ? entry.rwep_factors.blast_radius : 0,
|
|
138
|
+
patch_available: entry.patch_available,
|
|
139
|
+
live_patch_available: entry.live_patch_available,
|
|
140
|
+
reboot_required: entry.patch_required_reboot
|
|
141
|
+
});
|
|
142
|
+
if (Math.abs(calculatedRwep - entry.rwep_score) > 5) {
|
|
143
|
+
errors.push(`${cveId}: rwep_score ${entry.rwep_score} diverges from calculated ${calculatedRwep} by more than 5 — verify factors`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return errors;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
module.exports = { score, scoreCustom, timeline, compare, validate, RWEP_WEIGHTS };
|