@blamejs/exceptd-skills 0.10.0 → 0.10.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 +54 -0
- package/bin/exceptd.js +303 -9
- package/data/_indexes/_meta.json +2 -2
- package/data/playbooks/ai-api.json +400 -90
- package/data/playbooks/containers.json +406 -94
- package/data/playbooks/cred-stores.json +374 -89
- package/data/playbooks/crypto.json +369 -87
- package/data/playbooks/framework.json +376 -86
- package/data/playbooks/hardening.json +357 -84
- package/data/playbooks/kernel.json +324 -77
- package/data/playbooks/mcp.json +407 -92
- package/data/playbooks/runtime.json +345 -81
- package/data/playbooks/sbom.json +497 -111
- package/data/playbooks/secrets.json +352 -83
- package/lib/playbook-runner.js +77 -7
- package/lib/schemas/playbook.schema.json +5 -0
- package/manifest-snapshot.json +1 -1
- package/manifest.json +39 -39
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
|
@@ -9,11 +9,18 @@
|
|
|
9
9
|
"version": "1.0.0",
|
|
10
10
|
"date": "2026-05-11",
|
|
11
11
|
"summary": "Initial seven-phase container-escape posture playbook. Walks current repo for Dockerfile bases (--platform, FROM scratch, version-pinned vs. latest), docker-compose files (privileged, cap-add, host network), k8s manifests (hostPID/hostNetwork/hostIPC, privileged, runAsUser:0, missing seccompProfile). Cross-references runc / containerd / kubelet CVE lineage (Leaky Vessels CVE-2024-21626 class + subsequent breakouts). Closes GRC loop with NIST 800-190, CIS Kubernetes Benchmark, and supply-chain framework gap mapping.",
|
|
12
|
-
"framework_gaps_updated": [
|
|
12
|
+
"framework_gaps_updated": [
|
|
13
|
+
"nist-800-190",
|
|
14
|
+
"nist-800-53-CM-7",
|
|
15
|
+
"iso-27001-2022-A.8.9",
|
|
16
|
+
"pci-dss-4-req-2",
|
|
17
|
+
"cmmc-cm-l2-3.4.6"
|
|
18
|
+
]
|
|
13
19
|
}
|
|
14
20
|
],
|
|
15
21
|
"owner": "@blamejs/container-security",
|
|
16
22
|
"air_gap_mode": true,
|
|
23
|
+
"scope": "code",
|
|
17
24
|
"preconditions": [
|
|
18
25
|
{
|
|
19
26
|
"id": "repo-context",
|
|
@@ -34,23 +41,44 @@
|
|
|
34
41
|
}
|
|
35
42
|
]
|
|
36
43
|
},
|
|
37
|
-
|
|
38
44
|
"domain": {
|
|
39
45
|
"name": "Container runtime posture + manifest review",
|
|
40
46
|
"attack_class": "container-escape",
|
|
41
47
|
"atlas_refs": [],
|
|
42
|
-
"attack_refs": [
|
|
48
|
+
"attack_refs": [
|
|
49
|
+
"T1611",
|
|
50
|
+
"T1610",
|
|
51
|
+
"T1613",
|
|
52
|
+
"T1525",
|
|
53
|
+
"T1068"
|
|
54
|
+
],
|
|
43
55
|
"cve_refs": [],
|
|
44
|
-
"cwe_refs": [
|
|
45
|
-
|
|
56
|
+
"cwe_refs": [
|
|
57
|
+
"CWE-269",
|
|
58
|
+
"CWE-732",
|
|
59
|
+
"CWE-250",
|
|
60
|
+
"CWE-284",
|
|
61
|
+
"CWE-863"
|
|
62
|
+
],
|
|
63
|
+
"d3fend_refs": [
|
|
64
|
+
"D3-PA",
|
|
65
|
+
"D3-CBAN",
|
|
66
|
+
"D3-EI"
|
|
67
|
+
],
|
|
46
68
|
"frameworks_in_scope": [
|
|
47
|
-
"nist-800-53",
|
|
48
|
-
"
|
|
69
|
+
"nist-800-53",
|
|
70
|
+
"iso-27001-2022",
|
|
71
|
+
"soc2",
|
|
72
|
+
"pci-dss-4",
|
|
73
|
+
"nis2",
|
|
74
|
+
"dora",
|
|
75
|
+
"uk-caf",
|
|
76
|
+
"au-ism",
|
|
77
|
+
"au-essential-8",
|
|
78
|
+
"cmmc"
|
|
49
79
|
]
|
|
50
80
|
},
|
|
51
|
-
|
|
52
81
|
"phases": {
|
|
53
|
-
|
|
54
82
|
"govern": {
|
|
55
83
|
"jurisdiction_obligations": [
|
|
56
84
|
{
|
|
@@ -59,7 +87,11 @@
|
|
|
59
87
|
"obligation": "patch_critical",
|
|
60
88
|
"window_hours": 720,
|
|
61
89
|
"clock_starts": "analyze_complete",
|
|
62
|
-
"evidence_required": [
|
|
90
|
+
"evidence_required": [
|
|
91
|
+
"container_manifest_inventory",
|
|
92
|
+
"runtime_cve_status",
|
|
93
|
+
"remediation_plan"
|
|
94
|
+
]
|
|
63
95
|
},
|
|
64
96
|
{
|
|
65
97
|
"jurisdiction": "EU",
|
|
@@ -67,7 +99,10 @@
|
|
|
67
99
|
"obligation": "notify_regulator",
|
|
68
100
|
"window_hours": 24,
|
|
69
101
|
"clock_starts": "detect_confirmed",
|
|
70
|
-
"evidence_required": [
|
|
102
|
+
"evidence_required": [
|
|
103
|
+
"affected_workload_inventory",
|
|
104
|
+
"exploitation_status_assessment"
|
|
105
|
+
]
|
|
71
106
|
},
|
|
72
107
|
{
|
|
73
108
|
"jurisdiction": "US",
|
|
@@ -75,7 +110,10 @@
|
|
|
75
110
|
"obligation": "patch_critical",
|
|
76
111
|
"window_hours": 720,
|
|
77
112
|
"clock_starts": "validate_complete",
|
|
78
|
-
"evidence_required": [
|
|
113
|
+
"evidence_required": [
|
|
114
|
+
"baseline_configuration_document",
|
|
115
|
+
"ssp_section_update"
|
|
116
|
+
]
|
|
79
117
|
},
|
|
80
118
|
{
|
|
81
119
|
"jurisdiction": "AU",
|
|
@@ -83,7 +121,10 @@
|
|
|
83
121
|
"obligation": "notify_regulator",
|
|
84
122
|
"window_hours": 72,
|
|
85
123
|
"clock_starts": "validate_complete",
|
|
86
|
-
"evidence_required": [
|
|
124
|
+
"evidence_required": [
|
|
125
|
+
"materiality_assessment",
|
|
126
|
+
"remediation_completed_evidence"
|
|
127
|
+
]
|
|
87
128
|
}
|
|
88
129
|
],
|
|
89
130
|
"theater_fingerprints": [
|
|
@@ -91,25 +132,40 @@
|
|
|
91
132
|
"pattern_id": "cis-k8s-benchmark-attested-but-stale",
|
|
92
133
|
"claim": "We pass the CIS Kubernetes Benchmark / NIST 800-190 — container security covered.",
|
|
93
134
|
"fast_detection_test": "Walk the repo for k8s manifests and grep for privileged: true, hostPID: true, hostNetwork: true, hostIPC: true, runAsUser: 0, securityContext absent, seccompProfile absent. Any non-zero count in deployable manifests contradicts CIS K8s Section 5 / NIST 800-190 hardening claims regardless of cluster-wide attestation.",
|
|
94
|
-
"implicated_controls": [
|
|
135
|
+
"implicated_controls": [
|
|
136
|
+
"nist-800-190",
|
|
137
|
+
"nist-800-53-CM-7",
|
|
138
|
+
"iso-27001-2022-A.8.9"
|
|
139
|
+
]
|
|
95
140
|
},
|
|
96
141
|
{
|
|
97
142
|
"pattern_id": "image-scanning-attested-but-latest-tag",
|
|
98
143
|
"claim": "Container images are scanned for vulnerabilities in CI.",
|
|
99
144
|
"fast_detection_test": "Grep Dockerfiles for `FROM .*:latest` OR `FROM .*` (no tag at all). 'latest' resolves differently between scan time and deploy time; the scan result is for a different image than what ships. Any non-zero count makes the image-scanning attestation meaningless for the affected images.",
|
|
100
|
-
"implicated_controls": [
|
|
145
|
+
"implicated_controls": [
|
|
146
|
+
"nist-800-190-4.1.1",
|
|
147
|
+
"soc2-cc7.1",
|
|
148
|
+
"iso-27001-2022-A.8.8"
|
|
149
|
+
]
|
|
101
150
|
},
|
|
102
151
|
{
|
|
103
152
|
"pattern_id": "supply-chain-attested-but-no-pinning",
|
|
104
153
|
"claim": "We follow SLSA / NIST SSDF for container supply chain.",
|
|
105
154
|
"fast_detection_test": "Grep Dockerfiles for FROM with @sha256: digest pinning. Compare count of pinned vs. unpinned FROM directives. SLSA Level 3+ effectively requires digest pinning. Tag-only references without digest are theater for any SLSA L3+ attestation.",
|
|
106
|
-
"implicated_controls": [
|
|
155
|
+
"implicated_controls": [
|
|
156
|
+
"nist-ssdf-ps-3.2",
|
|
157
|
+
"nist-800-218",
|
|
158
|
+
"eu-cra"
|
|
159
|
+
]
|
|
107
160
|
},
|
|
108
161
|
{
|
|
109
162
|
"pattern_id": "runc-patched-but-no-version-evidence",
|
|
110
163
|
"claim": "Leaky Vessels (CVE-2024-21626 lineage) is patched cluster-wide.",
|
|
111
164
|
"fast_detection_test": "Ask the org for the kubectl version + node runc version on each pool. CVE-2024-21626 requires runc >= 1.1.12 OR containerd / Docker bundling a fixed runc. Without per-node version evidence, 'patched' is attested but not verified. Node staging windows can leave clusters mixed-patch for weeks.",
|
|
112
|
-
"implicated_controls": [
|
|
165
|
+
"implicated_controls": [
|
|
166
|
+
"nist-800-190",
|
|
167
|
+
"iso-27001-2022-A.8.8"
|
|
168
|
+
]
|
|
113
169
|
}
|
|
114
170
|
],
|
|
115
171
|
"framework_context": {
|
|
@@ -148,9 +204,14 @@
|
|
|
148
204
|
}
|
|
149
205
|
]
|
|
150
206
|
},
|
|
151
|
-
"skill_preload": [
|
|
207
|
+
"skill_preload": [
|
|
208
|
+
"container-runtime-security",
|
|
209
|
+
"supply-chain-integrity",
|
|
210
|
+
"framework-gap-analysis",
|
|
211
|
+
"compliance-theater",
|
|
212
|
+
"policy-exception-gen"
|
|
213
|
+
]
|
|
152
214
|
},
|
|
153
|
-
|
|
154
215
|
"direct": {
|
|
155
216
|
"threat_context": "Container escape attack class in 2025-2026 is dominated by the runc / containerd / kubelet CVE chain. CVE-2024-21626 'Leaky Vessels' (runc <1.1.12 working-directory race → fd leak into host) shipped Jan 2024 with public PoC and is the canonical container-escape primitive; subsequent runc/containerd CVEs follow the same pattern (host-resource leakage via misconfigured isolation). Mandiant 2025 IR report: ~22% of cloud-tenant compromises involved a container-escape step. The escape is exquisitely sensitive to manifest posture: privileged: true grants the attacker the full host kernel (LPE without escape); hostPID/hostNetwork/hostIPC grant cross-pod visibility; runAsUser: 0 + writable host mount = direct host write. seccompProfile + AppArmor profile presence is the primary mitigation. Manifests in repos are the attestation-vs-reality battleground — admission controllers reject some but not all anti-patterns, depending on policy maturity.",
|
|
156
217
|
"rwep_threshold": {
|
|
@@ -160,11 +221,32 @@
|
|
|
160
221
|
},
|
|
161
222
|
"framework_lag_declaration": "NIST 800-190 + CIS K8s Benchmark + NIST 800-53 CM-7 + ISO A.8.9 + PCI Req.2.2 collectively cover container hardening but accept cluster-wide attestation as evidence. None require per-manifest analysis as a control. Manifest drift in GitOps repos can introduce privileged: true / hostPID / unscoped capabilities faster than any attestation cadence. EU CRA + NIST SSDF + SLSA cover supply-chain posture but most orgs are at SLSA L1-L2 without digest pinning. Gap = ~21 days between manifest drift and review cadence; per-CVE gap (e.g. Leaky Vessels) is hours from public PoC to weaponization vs. weeks of node-staging windows.",
|
|
162
223
|
"skill_chain": [
|
|
163
|
-
{
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
224
|
+
{
|
|
225
|
+
"skill": "container-runtime-security",
|
|
226
|
+
"purpose": "Inventory Dockerfile + compose + k8s manifest posture; map to NIST 800-190 + CIS K8s Benchmark; identify per-manifest anti-patterns.",
|
|
227
|
+
"required": true
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
"skill": "supply-chain-integrity",
|
|
231
|
+
"purpose": "Assess image provenance: digest pinning, base-image lineage, signature verification, SBOM availability.",
|
|
232
|
+
"required": true
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
"skill": "framework-gap-analysis",
|
|
236
|
+
"purpose": "Map findings to which framework controls claim to cover them and where the gap is.",
|
|
237
|
+
"required": true
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
"skill": "compliance-theater",
|
|
241
|
+
"purpose": "Run the theater test on the org's container-security attestation (CIS K8s + image scanning + SLSA claim).",
|
|
242
|
+
"required": true
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
"skill": "policy-exception-gen",
|
|
246
|
+
"purpose": "Generate auditor-ready exception language for workloads requiring elevated privileges (CNI plugins, CSI drivers, eBPF observability) where the elevation is intentional.",
|
|
247
|
+
"skip_if": "close.exception_generation.trigger_condition == false",
|
|
248
|
+
"required": false
|
|
249
|
+
}
|
|
168
250
|
],
|
|
169
251
|
"token_budget": {
|
|
170
252
|
"estimated_total": 21000,
|
|
@@ -179,7 +261,6 @@
|
|
|
179
261
|
}
|
|
180
262
|
}
|
|
181
263
|
},
|
|
182
|
-
|
|
183
264
|
"look": {
|
|
184
265
|
"artifacts": [
|
|
185
266
|
{
|
|
@@ -272,16 +353,43 @@
|
|
|
272
353
|
}
|
|
273
354
|
],
|
|
274
355
|
"fallback_if_unavailable": [
|
|
275
|
-
{
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
{
|
|
281
|
-
|
|
356
|
+
{
|
|
357
|
+
"artifact_id": "dockerfile-inventory",
|
|
358
|
+
"fallback_action": "use_compensating_artifact",
|
|
359
|
+
"confidence_impact": "low"
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
"artifact_id": "compose-files",
|
|
363
|
+
"fallback_action": "use_compensating_artifact",
|
|
364
|
+
"confidence_impact": "low"
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
"artifact_id": "k8s-manifests",
|
|
368
|
+
"fallback_action": "use_compensating_artifact",
|
|
369
|
+
"confidence_impact": "medium"
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
"artifact_id": "helm-charts",
|
|
373
|
+
"fallback_action": "mark_inconclusive",
|
|
374
|
+
"confidence_impact": "low"
|
|
375
|
+
},
|
|
376
|
+
{
|
|
377
|
+
"artifact_id": "pod-security-admission-config",
|
|
378
|
+
"fallback_action": "mark_inconclusive",
|
|
379
|
+
"confidence_impact": "low"
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
"artifact_id": "network-policies",
|
|
383
|
+
"fallback_action": "mark_inconclusive",
|
|
384
|
+
"confidence_impact": "medium"
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
"artifact_id": "service-account-manifests",
|
|
388
|
+
"fallback_action": "mark_inconclusive",
|
|
389
|
+
"confidence_impact": "medium"
|
|
390
|
+
}
|
|
282
391
|
]
|
|
283
392
|
},
|
|
284
|
-
|
|
285
393
|
"detect": {
|
|
286
394
|
"indicators": [
|
|
287
395
|
{
|
|
@@ -458,30 +566,109 @@
|
|
|
458
566
|
"not_detected": "All container files inspected AND no deterministic indicators fired on workload-namespace manifests AND no more than one high-confidence indicator with confirmed benign distinguishing test."
|
|
459
567
|
}
|
|
460
568
|
},
|
|
461
|
-
|
|
462
569
|
"analyze": {
|
|
463
570
|
"rwep_inputs": [
|
|
464
|
-
{
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
{
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
571
|
+
{
|
|
572
|
+
"signal_id": "compose-privileged",
|
|
573
|
+
"rwep_factor": "active_exploitation",
|
|
574
|
+
"weight": 30,
|
|
575
|
+
"notes": "privileged: true is exploitation-already-configured."
|
|
576
|
+
},
|
|
577
|
+
{
|
|
578
|
+
"signal_id": "k8s-privileged",
|
|
579
|
+
"rwep_factor": "active_exploitation",
|
|
580
|
+
"weight": 30,
|
|
581
|
+
"notes": "Same as compose-privileged."
|
|
582
|
+
},
|
|
583
|
+
{
|
|
584
|
+
"signal_id": "compose-docker-sock-mount",
|
|
585
|
+
"rwep_factor": "active_exploitation",
|
|
586
|
+
"weight": 30,
|
|
587
|
+
"notes": "Docker socket mount = full host control."
|
|
588
|
+
},
|
|
589
|
+
{
|
|
590
|
+
"signal_id": "k8s-hostpath-sensitive",
|
|
591
|
+
"rwep_factor": "active_exploitation",
|
|
592
|
+
"weight": 25,
|
|
593
|
+
"notes": "Sensitive host path mount = direct host write."
|
|
594
|
+
},
|
|
595
|
+
{
|
|
596
|
+
"signal_id": "k8s-host-namespaces",
|
|
597
|
+
"rwep_factor": "blast_radius",
|
|
598
|
+
"weight": 20,
|
|
599
|
+
"notes": "Host namespace = cross-process pivot."
|
|
600
|
+
},
|
|
601
|
+
{
|
|
602
|
+
"signal_id": "compose-host-network",
|
|
603
|
+
"rwep_factor": "blast_radius",
|
|
604
|
+
"weight": 20,
|
|
605
|
+
"notes": "Same."
|
|
606
|
+
},
|
|
607
|
+
{
|
|
608
|
+
"signal_id": "k8s-cluster-admin-binding",
|
|
609
|
+
"rwep_factor": "active_exploitation",
|
|
610
|
+
"weight": 30,
|
|
611
|
+
"notes": "Cluster-admin SA in workload namespace = pre-positioned escalation."
|
|
612
|
+
},
|
|
613
|
+
{
|
|
614
|
+
"signal_id": "k8s-run-as-root",
|
|
615
|
+
"rwep_factor": "blast_radius",
|
|
616
|
+
"weight": 15,
|
|
617
|
+
"notes": "Root inside container amplifies any escape primitive."
|
|
618
|
+
},
|
|
619
|
+
{
|
|
620
|
+
"signal_id": "k8s-no-seccomp-profile",
|
|
621
|
+
"rwep_factor": "blast_radius",
|
|
622
|
+
"weight": 10,
|
|
623
|
+
"notes": "Unconfined syscalls = full escape primitive surface."
|
|
624
|
+
},
|
|
625
|
+
{
|
|
626
|
+
"signal_id": "k8s-image-latest",
|
|
627
|
+
"rwep_factor": "ai_weaponization",
|
|
628
|
+
"weight": 10,
|
|
629
|
+
"notes": "Image mutation between scan and deploy creates an AI-discoverable attack window."
|
|
630
|
+
},
|
|
631
|
+
{
|
|
632
|
+
"signal_id": "dockerfile-from-latest",
|
|
633
|
+
"rwep_factor": "ai_weaponization",
|
|
634
|
+
"weight": 10,
|
|
635
|
+
"notes": "Same — build vs. deploy provenance gap."
|
|
636
|
+
},
|
|
637
|
+
{
|
|
638
|
+
"signal_id": "dockerfile-curl-pipe-bash",
|
|
639
|
+
"rwep_factor": "active_exploitation",
|
|
640
|
+
"weight": 20,
|
|
641
|
+
"notes": "Supply-chain build primitive."
|
|
642
|
+
}
|
|
476
643
|
],
|
|
477
644
|
"blast_radius_model": {
|
|
478
645
|
"scope_question": "Given the manifest posture, what is the realistic blast radius when this workload is deployed and an attacker achieves code execution inside the container?",
|
|
479
646
|
"scoring_rubric": [
|
|
480
|
-
{
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
647
|
+
{
|
|
648
|
+
"condition": "No deterministic indicators on workload-namespace manifests AND digest pinning + non-root + seccomp profile present",
|
|
649
|
+
"blast_radius_score": 1,
|
|
650
|
+
"description": "Container is hardened. Escape requires a runtime CVE chain; no pre-positioned primitives."
|
|
651
|
+
},
|
|
652
|
+
{
|
|
653
|
+
"condition": "One high-confidence indicator (e.g. no seccomp, or no digest pin) on otherwise-hardened manifest",
|
|
654
|
+
"blast_radius_score": 2,
|
|
655
|
+
"description": "Single hardening gap. Escape requires both a runtime CVE and the gap."
|
|
656
|
+
},
|
|
657
|
+
{
|
|
658
|
+
"condition": "One deterministic indicator (privileged: false but hostPath sensitive, OR latest tag) on a workload manifest",
|
|
659
|
+
"blast_radius_score": 3,
|
|
660
|
+
"description": "One pre-positioned escape primitive. Container compromise → host with manageable effort."
|
|
661
|
+
},
|
|
662
|
+
{
|
|
663
|
+
"condition": "Multiple deterministic indicators on workload manifest OR cluster-admin SA in workload namespace",
|
|
664
|
+
"blast_radius_score": 4,
|
|
665
|
+
"description": "Container compromise = cluster-wide compromise without runtime CVE chain."
|
|
666
|
+
},
|
|
667
|
+
{
|
|
668
|
+
"condition": "privileged: true + hostPID/Network + docker.sock mount + cluster-admin SA on workload-namespace pod",
|
|
669
|
+
"blast_radius_score": 5,
|
|
670
|
+
"description": "Pre-positioned host-and-cluster compromise. Pod compromise = full infrastructure access."
|
|
671
|
+
}
|
|
485
672
|
]
|
|
486
673
|
},
|
|
487
674
|
"compliance_theater_check": {
|
|
@@ -528,85 +715,143 @@
|
|
|
528
715
|
}
|
|
529
716
|
],
|
|
530
717
|
"escalation_criteria": [
|
|
531
|
-
{
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
718
|
+
{
|
|
719
|
+
"condition": "rwep >= 90 AND blast_radius_score >= 4",
|
|
720
|
+
"action": "page_on_call"
|
|
721
|
+
},
|
|
722
|
+
{
|
|
723
|
+
"condition": "k8s-cluster-admin-binding fired AND target_namespace not in infrastructure_namespaces",
|
|
724
|
+
"action": "raise_severity"
|
|
725
|
+
},
|
|
726
|
+
{
|
|
727
|
+
"condition": "blast_radius_score >= 4 AND workload_is_internet_facing == true",
|
|
728
|
+
"action": "trigger_playbook",
|
|
729
|
+
"target_playbook": "secrets"
|
|
730
|
+
},
|
|
731
|
+
{
|
|
732
|
+
"condition": "compliance_theater_check.verdict == 'theater' AND jurisdiction_obligations contains 'EU'",
|
|
733
|
+
"action": "notify_legal"
|
|
734
|
+
}
|
|
535
735
|
]
|
|
536
736
|
},
|
|
537
|
-
|
|
538
737
|
"validate": {
|
|
539
738
|
"remediation_paths": [
|
|
540
739
|
{
|
|
541
740
|
"id": "remove-privileged-flag",
|
|
542
741
|
"description": "Refactor manifest to remove privileged: true. If workload needs specific capability, replace with bounded capabilities: add: [NET_ADMIN] etc. and drop: [ALL]. If host access genuinely required (eBPF observability), move workload to a dedicated infrastructure namespace + document via PodSecurity exemption.",
|
|
543
|
-
"preconditions": [
|
|
742
|
+
"preconditions": [
|
|
743
|
+
"workload_owner_consulted == true",
|
|
744
|
+
"alternative_capability_path_identified == true"
|
|
745
|
+
],
|
|
544
746
|
"priority": 1,
|
|
545
|
-
"compensating_controls": [
|
|
747
|
+
"compensating_controls": [
|
|
748
|
+
"pod-security-baseline-enforced",
|
|
749
|
+
"admission-controller-blocks-privileged"
|
|
750
|
+
],
|
|
546
751
|
"estimated_time_hours": 2
|
|
547
752
|
},
|
|
548
753
|
{
|
|
549
754
|
"id": "remove-host-namespaces",
|
|
550
755
|
"description": "Remove hostPID / hostNetwork / hostIPC from workload manifests. Move legitimate host-namespace consumers to infrastructure namespaces with documented exemption.",
|
|
551
|
-
"preconditions": [
|
|
756
|
+
"preconditions": [
|
|
757
|
+
"workload_owner_consulted == true",
|
|
758
|
+
"host_namespace_requirement_documented_or_invalid == true"
|
|
759
|
+
],
|
|
552
760
|
"priority": 1,
|
|
553
|
-
"compensating_controls": [
|
|
761
|
+
"compensating_controls": [
|
|
762
|
+
"pod-security-baseline-enforced",
|
|
763
|
+
"namespace-isolation-tightened"
|
|
764
|
+
],
|
|
554
765
|
"estimated_time_hours": 2
|
|
555
766
|
},
|
|
556
767
|
{
|
|
557
768
|
"id": "pin-images-by-digest",
|
|
558
769
|
"description": "Replace image: name:tag with image: name@sha256:digest in k8s manifests; replace FROM name:tag with FROM name@sha256:digest in Dockerfiles. Automate digest resolution in CI.",
|
|
559
|
-
"preconditions": [
|
|
770
|
+
"preconditions": [
|
|
771
|
+
"ci_supports_digest_resolution == true OR manual_digest_pinning_accepted == true"
|
|
772
|
+
],
|
|
560
773
|
"priority": 2,
|
|
561
|
-
"compensating_controls": [
|
|
774
|
+
"compensating_controls": [
|
|
775
|
+
"image-signature-verified",
|
|
776
|
+
"registry-immutability-enforced"
|
|
777
|
+
],
|
|
562
778
|
"estimated_time_hours": 4
|
|
563
779
|
},
|
|
564
780
|
{
|
|
565
781
|
"id": "set-runasnonroot",
|
|
566
782
|
"description": "Add securityContext.runAsNonRoot: true and runAsUser: <non-zero> to all workload pods. Update Dockerfile USER directives accordingly.",
|
|
567
|
-
"preconditions": [
|
|
783
|
+
"preconditions": [
|
|
784
|
+
"image_supports_non_root == true"
|
|
785
|
+
],
|
|
568
786
|
"priority": 2,
|
|
569
|
-
"compensating_controls": [
|
|
787
|
+
"compensating_controls": [
|
|
788
|
+
"pod-security-restricted-enforced"
|
|
789
|
+
],
|
|
570
790
|
"estimated_time_hours": 2
|
|
571
791
|
},
|
|
572
792
|
{
|
|
573
793
|
"id": "add-seccomp-profile",
|
|
574
794
|
"description": "Add seccompProfile.type: RuntimeDefault (or Localhost with specific profile) to pod or container securityContext. Or enable cluster-wide --seccomp-default at kubelet.",
|
|
575
|
-
"preconditions": [
|
|
795
|
+
"preconditions": [
|
|
796
|
+
"cluster_supports_seccomp_profile == true"
|
|
797
|
+
],
|
|
576
798
|
"priority": 2,
|
|
577
|
-
"compensating_controls": [
|
|
799
|
+
"compensating_controls": [
|
|
800
|
+
"seccomp-profile-active"
|
|
801
|
+
],
|
|
578
802
|
"estimated_time_hours": 1
|
|
579
803
|
},
|
|
580
804
|
{
|
|
581
805
|
"id": "remove-docker-sock-mount",
|
|
582
806
|
"description": "Remove /var/run/docker.sock from container volumes. If workload genuinely needs to orchestrate containers, switch to (a) kubernetes API client with bounded SA permissions, (b) BuildKit / Buildah daemonless build, or (c) sysbox or kata for hardened nested runtime.",
|
|
583
|
-
"preconditions": [
|
|
807
|
+
"preconditions": [
|
|
808
|
+
"alternative_path_identified == true"
|
|
809
|
+
],
|
|
584
810
|
"priority": 1,
|
|
585
|
-
"compensating_controls": [
|
|
811
|
+
"compensating_controls": [
|
|
812
|
+
"bounded-rbac-applied",
|
|
813
|
+
"sysbox-or-kata-deployed"
|
|
814
|
+
],
|
|
586
815
|
"estimated_time_hours": 4
|
|
587
816
|
},
|
|
588
817
|
{
|
|
589
818
|
"id": "scope-cluster-admin-binding",
|
|
590
819
|
"description": "Replace cluster-admin ClusterRoleBinding for workload SAs with namespace-scoped Role + RoleBinding granting only required verbs/resources. Audit current usage first to enumerate required permissions.",
|
|
591
|
-
"preconditions": [
|
|
820
|
+
"preconditions": [
|
|
821
|
+
"sa_usage_audit_complete == true"
|
|
822
|
+
],
|
|
592
823
|
"priority": 1,
|
|
593
|
-
"compensating_controls": [
|
|
824
|
+
"compensating_controls": [
|
|
825
|
+
"scoped-role-applied",
|
|
826
|
+
"audit2rbac-output-attached"
|
|
827
|
+
],
|
|
594
828
|
"estimated_time_hours": 6
|
|
595
829
|
},
|
|
596
830
|
{
|
|
597
831
|
"id": "update-runtime-patches",
|
|
598
832
|
"description": "Confirm runc >= 1.1.12, containerd patched against current CVE lineage, kubelet at minimum supported minor. Coordinate node-by-node patch rollout.",
|
|
599
|
-
"preconditions": [
|
|
833
|
+
"preconditions": [
|
|
834
|
+
"maintenance_window_available == true"
|
|
835
|
+
],
|
|
600
836
|
"priority": 2,
|
|
601
|
-
"compensating_controls": [
|
|
837
|
+
"compensating_controls": [
|
|
838
|
+
"node-cordon-drain-update-uncordon-pattern"
|
|
839
|
+
],
|
|
602
840
|
"estimated_time_hours": 12
|
|
603
841
|
},
|
|
604
842
|
{
|
|
605
843
|
"id": "policy-exception",
|
|
606
844
|
"description": "For workloads requiring elevated privileges that cannot be remediated (CNI, CSI, eBPF observability, specific HPC workloads), generate auditor-ready exception with named compensating controls.",
|
|
607
|
-
"preconditions": [
|
|
845
|
+
"preconditions": [
|
|
846
|
+
"elevation_documented_as_required == true",
|
|
847
|
+
"infrastructure_namespace_designated == true"
|
|
848
|
+
],
|
|
608
849
|
"priority": 4,
|
|
609
|
-
"compensating_controls": [
|
|
850
|
+
"compensating_controls": [
|
|
851
|
+
"namespace-isolation-enforced",
|
|
852
|
+
"audit-log-monitoring-on-workload",
|
|
853
|
+
"runtime-policy-tightened-on-workload"
|
|
854
|
+
],
|
|
610
855
|
"estimated_time_hours": 4
|
|
611
856
|
}
|
|
612
857
|
],
|
|
@@ -652,46 +897,87 @@
|
|
|
652
897
|
"risk": "Even with hardened manifests, runtime CVEs in runc / containerd / kubelet emerge regularly. A hardened manifest reduces blast radius of an exploited runtime CVE but does not prevent the CVE itself. Additionally, supply-chain compromise of the base image cannot be prevented by manifest posture.",
|
|
653
898
|
"why_remains": "Container security is layered defense. Hardened manifests + admission control + image signing + runtime security + node hardening together provide defense in depth; no single layer is sufficient.",
|
|
654
899
|
"acceptance_level": "manager",
|
|
655
|
-
"compensating_controls_in_place": [
|
|
900
|
+
"compensating_controls_in_place": [
|
|
901
|
+
"admission-controller-baseline",
|
|
902
|
+
"image-signatures-verified",
|
|
903
|
+
"runtime-security-monitoring",
|
|
904
|
+
"node-hardening-baselined",
|
|
905
|
+
"monthly-manifest-cadence"
|
|
906
|
+
]
|
|
656
907
|
},
|
|
657
908
|
"evidence_requirements": [
|
|
658
909
|
{
|
|
659
910
|
"evidence_type": "scan_report",
|
|
660
911
|
"description": "Full manifest walk output: per-file indicator firing counts, RWEP per workload, before-after diff.",
|
|
661
912
|
"retention_period": "1_year",
|
|
662
|
-
"framework_satisfied": [
|
|
913
|
+
"framework_satisfied": [
|
|
914
|
+
"nist-800-190",
|
|
915
|
+
"nist-800-53-CM-7",
|
|
916
|
+
"iso-27001-2022-A.8.9",
|
|
917
|
+
"cmmc-cm-l2-3.4.6"
|
|
918
|
+
]
|
|
663
919
|
},
|
|
664
920
|
{
|
|
665
921
|
"evidence_type": "config_diff",
|
|
666
922
|
"description": "Pre/post manifest diffs showing remediation applied; admission controller config history.",
|
|
667
923
|
"retention_period": "7_years",
|
|
668
|
-
"framework_satisfied": [
|
|
924
|
+
"framework_satisfied": [
|
|
925
|
+
"nist-800-53-CM-3",
|
|
926
|
+
"iso-27001-2022-A.8.32"
|
|
927
|
+
]
|
|
669
928
|
},
|
|
670
929
|
{
|
|
671
930
|
"evidence_type": "patch_record",
|
|
672
931
|
"description": "Per-node runc / containerd / kubelet version evidence with patch deployment timestamps.",
|
|
673
932
|
"retention_period": "7_years",
|
|
674
|
-
"framework_satisfied": [
|
|
933
|
+
"framework_satisfied": [
|
|
934
|
+
"nist-800-53-SI-2",
|
|
935
|
+
"iso-27001-2022-A.8.8",
|
|
936
|
+
"nis2-art21-2c"
|
|
937
|
+
]
|
|
675
938
|
},
|
|
676
939
|
{
|
|
677
940
|
"evidence_type": "attestation",
|
|
678
941
|
"description": "Signed exceptd attestation: repo identity, manifest count, indicator firing counts, runtime versions, RWEP at detection, RWEP post-remediation.",
|
|
679
942
|
"retention_period": "7_years",
|
|
680
|
-
"framework_satisfied": [
|
|
943
|
+
"framework_satisfied": [
|
|
944
|
+
"nist-800-53-CA-7",
|
|
945
|
+
"iso-27001-2022-A.5.36",
|
|
946
|
+
"nis2-art21-2c"
|
|
947
|
+
]
|
|
681
948
|
}
|
|
682
949
|
],
|
|
683
950
|
"regression_trigger": [
|
|
684
|
-
{
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
951
|
+
{
|
|
952
|
+
"condition": "post_helm_or_kustomize_change",
|
|
953
|
+
"interval": "on_event"
|
|
954
|
+
},
|
|
955
|
+
{
|
|
956
|
+
"condition": "new_cve_in_container_runtime",
|
|
957
|
+
"interval": "on_event"
|
|
958
|
+
},
|
|
959
|
+
{
|
|
960
|
+
"condition": "monthly",
|
|
961
|
+
"interval": "30d"
|
|
962
|
+
},
|
|
963
|
+
{
|
|
964
|
+
"condition": "post_admission_controller_policy_change",
|
|
965
|
+
"interval": "on_event"
|
|
966
|
+
}
|
|
688
967
|
]
|
|
689
968
|
},
|
|
690
|
-
|
|
691
969
|
"close": {
|
|
692
970
|
"evidence_package": {
|
|
693
971
|
"bundle_format": "csaf-2.0",
|
|
694
|
-
"contents": [
|
|
972
|
+
"contents": [
|
|
973
|
+
"scan_report",
|
|
974
|
+
"config_diff",
|
|
975
|
+
"patch_record",
|
|
976
|
+
"attestation",
|
|
977
|
+
"framework_gap_mapping",
|
|
978
|
+
"compliance_theater_verdict",
|
|
979
|
+
"residual_risk_statement"
|
|
980
|
+
],
|
|
695
981
|
"destination": "local_only",
|
|
696
982
|
"signed": true
|
|
697
983
|
},
|
|
@@ -703,28 +989,43 @@
|
|
|
703
989
|
"framework_gap": "Cluster-wide attestation cadence + per-workload manifest velocity creates structural drift window. Runtime CVE patch tempo + node staging window creates separate drift. Frameworks lag both by ~21 days.",
|
|
704
990
|
"new_control_requirement": "Per-manifest analysis at admission time + per-node runtime version evidence + digest-pinned images + signed image verification become required baseline controls. Continuous attestation replaces point-in-time CIS scans."
|
|
705
991
|
},
|
|
706
|
-
"feeds_back_to_skills": [
|
|
992
|
+
"feeds_back_to_skills": [
|
|
993
|
+
"container-runtime-security",
|
|
994
|
+
"supply-chain-integrity",
|
|
995
|
+
"framework-gap-analysis",
|
|
996
|
+
"compliance-theater"
|
|
997
|
+
]
|
|
707
998
|
},
|
|
708
999
|
"notification_actions": [
|
|
709
1000
|
{
|
|
710
1001
|
"obligation_ref": "EU/NIS2 Art.21 720h",
|
|
711
1002
|
"deadline": "computed_at_runtime",
|
|
712
1003
|
"recipient": "internal_legal",
|
|
713
|
-
"evidence_attached": [
|
|
1004
|
+
"evidence_attached": [
|
|
1005
|
+
"container_manifest_inventory",
|
|
1006
|
+
"runtime_cve_status",
|
|
1007
|
+
"remediation_plan"
|
|
1008
|
+
],
|
|
714
1009
|
"draft_notification": "NIS2 Art.21 vulnerability-handling record: Container posture review on ${affected_workload_count} workload(s) and ${node_count} node(s). Findings: ${finding_summary}. Remediation completed by ${remediation_date}. Container runtime versions: ${runtime_version_summary}. Evidence: manifest inventory + runtime CVE status + remediation plan attached."
|
|
715
1010
|
},
|
|
716
1011
|
{
|
|
717
1012
|
"obligation_ref": "EU/NIS2 Art.23 24h",
|
|
718
1013
|
"deadline": "computed_at_runtime",
|
|
719
1014
|
"recipient": "internal_legal",
|
|
720
|
-
"evidence_attached": [
|
|
1015
|
+
"evidence_attached": [
|
|
1016
|
+
"affected_workload_inventory",
|
|
1017
|
+
"exploitation_status_assessment"
|
|
1018
|
+
],
|
|
721
1019
|
"draft_notification": "NIS2 Art.23 early-warning notification: Container-escape-related finding on ${affected_workload_count} workload(s). Indicator(s): ${indicator_summary}. Interim mitigation: ${interim_mitigation}. Full incident assessment within 72h per Art.23(4)."
|
|
722
1020
|
},
|
|
723
1021
|
{
|
|
724
1022
|
"obligation_ref": "US/CMMC 2.0 CM.L2-3.4.6 720h",
|
|
725
1023
|
"deadline": "computed_at_runtime",
|
|
726
1024
|
"recipient": "internal_legal",
|
|
727
|
-
"evidence_attached": [
|
|
1025
|
+
"evidence_attached": [
|
|
1026
|
+
"baseline_configuration_document",
|
|
1027
|
+
"ssp_section_update"
|
|
1028
|
+
],
|
|
728
1029
|
"draft_notification": "CMMC CM.L2-3.4.6 update: Container baseline configuration review completed on ${affected_workload_count} workload(s). Baseline updates: ${baseline_updates}. SSP section to update: ${ssp_section}. Continuous-monitoring evidence retained."
|
|
729
1030
|
}
|
|
730
1031
|
],
|
|
@@ -733,7 +1034,13 @@
|
|
|
733
1034
|
"exception_template": {
|
|
734
1035
|
"scope": "Container privilege elevation OR unpatched runtime on ${affected_workload_count} workload(s) / ${node_count} node(s). Elevation reason: ${elevation_reason}.",
|
|
735
1036
|
"duration": "until_next_audit",
|
|
736
|
-
"compensating_controls": [
|
|
1037
|
+
"compensating_controls": [
|
|
1038
|
+
"namespace-isolation-enforced",
|
|
1039
|
+
"network-policy-restrictive",
|
|
1040
|
+
"runtime-security-monitoring-active",
|
|
1041
|
+
"audit-log-monitoring-on-workload",
|
|
1042
|
+
"admission-controller-exemption-documented"
|
|
1043
|
+
],
|
|
737
1044
|
"risk_acceptance_owner": "manager",
|
|
738
1045
|
"auditor_ready_language": "Pursuant to ${framework_id} ${control_id}, the organization documents a time-bound risk acceptance for container privilege configuration ${elevation_class} on ${affected_workload_count} workload(s) and/or runtime version exposure on ${node_count} node(s). Elevation reason: ${elevation_reason_narrative}. Workload(s) deployed in dedicated infrastructure namespace ${namespace_name} with restrictive network policy and runtime security monitoring. Compensating controls in place: ${compensating_controls}. Residual exposure: workload retains elevated privileges; runtime CVE patch deployment subject to node staging window. Risk accepted by ${manager_name} on ${acceptance_date}. Time-bound until ${duration_expiry} OR runtime patch completion + workload refactor completion, whichever is first. Detection coverage during the exception window: ${detection_controls}. Re-evaluation triggers: (a) workload refactor to remove elevation, (b) runtime patch completion, (c) listed expiry date, (d) any runtime security event on the workload — whichever is first."
|
|
739
1046
|
}
|
|
@@ -745,22 +1052,27 @@
|
|
|
745
1052
|
}
|
|
746
1053
|
}
|
|
747
1054
|
},
|
|
748
|
-
|
|
749
1055
|
"directives": [
|
|
750
1056
|
{
|
|
751
1057
|
"id": "full-container-manifest-walk",
|
|
752
1058
|
"title": "Full container manifest walk — Dockerfile + compose + k8s + helm",
|
|
753
|
-
"applies_to": {
|
|
1059
|
+
"applies_to": {
|
|
1060
|
+
"always": true
|
|
1061
|
+
}
|
|
754
1062
|
},
|
|
755
1063
|
{
|
|
756
1064
|
"id": "container-escape-primitives",
|
|
757
1065
|
"title": "Targeted directive — manifests pre-positioning container escape primitives",
|
|
758
|
-
"applies_to": {
|
|
1066
|
+
"applies_to": {
|
|
1067
|
+
"attack_technique": "T1611"
|
|
1068
|
+
}
|
|
759
1069
|
},
|
|
760
1070
|
{
|
|
761
1071
|
"id": "supply-chain-image-provenance",
|
|
762
1072
|
"title": "Targeted directive — image provenance + digest pinning + signature verification",
|
|
763
|
-
"applies_to": {
|
|
1073
|
+
"applies_to": {
|
|
1074
|
+
"attack_technique": "T1525"
|
|
1075
|
+
}
|
|
764
1076
|
}
|
|
765
1077
|
]
|
|
766
1078
|
}
|