attackmap 0.6.4__py3-none-any.whl
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.
- attackmap/__init__.py +2 -0
- attackmap/analyzer.py +449 -0
- attackmap/analyzer_contracts.py +194 -0
- attackmap/analyzers.py +1003 -0
- attackmap/anomalies.py +612 -0
- attackmap/asset_model.py +245 -0
- attackmap/attack_taxonomy.py +133 -0
- attackmap/auth_protocol.py +702 -0
- attackmap/authz.py +1695 -0
- attackmap/bench.py +467 -0
- attackmap/cli.py +1474 -0
- attackmap/config_scanner.py +389 -0
- attackmap/context_pack.py +82 -0
- attackmap/contracts.py +201 -0
- attackmap/control_model.py +280 -0
- attackmap/crossrepo.py +356 -0
- attackmap/crypto.py +240 -0
- attackmap/cve.py +717 -0
- attackmap/defensive_review.py +647 -0
- attackmap/detection_opportunities.py +1221 -0
- attackmap/detections/__init__.py +491 -0
- attackmap/detections/bola.yml +57 -0
- attackmap/detections/cloud.yml +609 -0
- attackmap/detections/injection.yml +167 -0
- attackmap/detections/secrets.yml +48 -0
- attackmap/detections/sigma.py +511 -0
- attackmap/detections/ssrf.yml +98 -0
- attackmap/detections/weakness.yml +62 -0
- attackmap/detections/webhook.yml +45 -0
- attackmap/detections/workflow.yml +121 -0
- attackmap/diagrams.py +237 -0
- attackmap/diff.py +301 -0
- attackmap/exploitability.py +493 -0
- attackmap/fingerprint.py +91 -0
- attackmap/fleet.py +370 -0
- attackmap/gitref.py +129 -0
- attackmap/graph.py +26 -0
- attackmap/handler_auth.py +639 -0
- attackmap/handler_span.py +62 -0
- attackmap/hunt_harness.py +505 -0
- attackmap/insights.py +701 -0
- attackmap/llm_review.py +846 -0
- attackmap/lockfiles.py +521 -0
- attackmap/mass_assignment.py +543 -0
- attackmap/md.py +175 -0
- attackmap/merge.py +333 -0
- attackmap/models.py +1284 -0
- attackmap/plugins_lock.py +114 -0
- attackmap/popular_packages.py +193 -0
- attackmap/progress.py +258 -0
- attackmap/recon_models.py +31 -0
- attackmap/recon_to_analysis.py +149 -0
- attackmap/redact.py +220 -0
- attackmap/report.py +424 -0
- attackmap/review_eval.py +335 -0
- attackmap/review_json.py +308 -0
- attackmap/review_prompts.py +796 -0
- attackmap/route_auth_fusion.py +474 -0
- attackmap/safe_fs.py +285 -0
- attackmap/sarif.py +373 -0
- attackmap/sbom.py +418 -0
- attackmap/scanner.py +1379 -0
- attackmap/sdk/__init__.py +278 -0
- attackmap/sdk/contracts.py +17 -0
- attackmap/sdk/fs.py +156 -0
- attackmap/sdk/models.py +59 -0
- attackmap/secrets_history.py +161 -0
- attackmap/security_overlay.py +71 -0
- attackmap/srcpaths.py +301 -0
- attackmap/suggest.py +394 -0
- attackmap/supply_chain.py +688 -0
- attackmap/suppress.py +740 -0
- attackmap/taint.py +1540 -0
- attackmap/taint_flow.py +1419 -0
- attackmap/taint_sinks.py +431 -0
- attackmap/taint_sinks.yaml +308 -0
- attackmap/taint_sources.py +396 -0
- attackmap/taxonomy.py +465 -0
- attackmap/threat_model.py +3441 -0
- attackmap/topology.py +316 -0
- attackmap/triage.py +151 -0
- attackmap/weaknesses.py +365 -0
- attackmap/webhardening.py +479 -0
- attackmap/webhook_verification.py +1067 -0
- attackmap/workflow_scanner.py +964 -0
- attackmap-0.6.4.dist-info/METADATA +226 -0
- attackmap-0.6.4.dist-info/RECORD +91 -0
- attackmap-0.6.4.dist-info/WHEEL +5 -0
- attackmap-0.6.4.dist-info/entry_points.txt +2 -0
- attackmap-0.6.4.dist-info/licenses/LICENSE +21 -0
- attackmap-0.6.4.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,609 @@
|
|
|
1
|
+
# Cloud and Kubernetes misconfiguration rules (#351), keyed by the
|
|
2
|
+
# CloudMisconfig rule ids (#334). Each rule watches the control plane for the
|
|
3
|
+
# risky setting being applied: the Kubernetes API audit log for workloads and
|
|
4
|
+
# RBAC, CloudTrail for AWS resources. Every selection needs the risky
|
|
5
|
+
# attribute itself (privileged: true, a 0.0.0.0/0 range, roleRef
|
|
6
|
+
# cluster-admin), never a bare event name.
|
|
7
|
+
#
|
|
8
|
+
# Audit and CloudTrail events nest arrays (containers, rules, ipRanges). The
|
|
9
|
+
# field paths below are the dotted, array-flattened names most pipelines
|
|
10
|
+
# produce (Elastic, Splunk spath, Sentinel parse_json). Kubernetes rules on
|
|
11
|
+
# requestObject need audit level Request or RequestResponse for these
|
|
12
|
+
# resources. Map the names to your pipeline.
|
|
13
|
+
|
|
14
|
+
templates:
|
|
15
|
+
k8s-privileged-workload:
|
|
16
|
+
date: "2026-10-12"
|
|
17
|
+
title: "Kubernetes workload created or changed with a privileged container"
|
|
18
|
+
description: >-
|
|
19
|
+
A pod or workload controller (including CronJob job templates and
|
|
20
|
+
init or ephemeral containers) is created or updated with a container
|
|
21
|
+
running privileged (full access to the node). AttackMap found
|
|
22
|
+
privileged containers in ${locations} (rule ${rule_id}); applying such a
|
|
23
|
+
spec is the step that hands an attacker in the container the node.
|
|
24
|
+
logsource: {product: kubernetes, service: audit}
|
|
25
|
+
fields_required: [verb, objectRef.resource, objectRef.namespace, objectRef.name, user.username, requestObject.spec.containers.securityContext.privileged, requestObject.spec.template.spec.containers.securityContext.privileged, requestObject.spec.jobTemplate.spec.template.spec.containers.securityContext.privileged]
|
|
26
|
+
detection:
|
|
27
|
+
selection_write:
|
|
28
|
+
verb: [create, update, patch]
|
|
29
|
+
objectRef.resource: [pods, deployments, daemonsets, statefulsets, replicasets, replicationcontrollers, jobs, cronjobs]
|
|
30
|
+
priv_any:
|
|
31
|
+
- requestObject.spec.containers.securityContext.privileged: true
|
|
32
|
+
- requestObject.spec.initContainers.securityContext.privileged: true
|
|
33
|
+
- requestObject.spec.ephemeralContainers.securityContext.privileged: true
|
|
34
|
+
- requestObject.spec.template.spec.containers.securityContext.privileged: true
|
|
35
|
+
- requestObject.spec.template.spec.initContainers.securityContext.privileged: true
|
|
36
|
+
- requestObject.spec.template.spec.ephemeralContainers.securityContext.privileged: true
|
|
37
|
+
- requestObject.spec.jobTemplate.spec.template.spec.containers.securityContext.privileged: true
|
|
38
|
+
- requestObject.spec.jobTemplate.spec.template.spec.initContainers.securityContext.privileged: true
|
|
39
|
+
- requestObject.spec.jobTemplate.spec.template.spec.ephemeralContainers.securityContext.privileged: true
|
|
40
|
+
condition: selection_write and priv_any
|
|
41
|
+
falsepositives:
|
|
42
|
+
- CNI, CSI and monitoring agents that need privileged mode (exclude their namespaces, e.g. kube-system)
|
|
43
|
+
level: high
|
|
44
|
+
test_events:
|
|
45
|
+
positive:
|
|
46
|
+
- verb: create
|
|
47
|
+
objectRef.resource: daemonsets
|
|
48
|
+
objectRef.namespace: default
|
|
49
|
+
user.username: alice
|
|
50
|
+
requestObject.spec.template.spec.containers.securityContext.privileged: true
|
|
51
|
+
negative:
|
|
52
|
+
- verb: create
|
|
53
|
+
objectRef.resource: deployments
|
|
54
|
+
objectRef.namespace: default
|
|
55
|
+
user.username: alice
|
|
56
|
+
requestObject.spec.template.spec.containers.securityContext.privileged: false
|
|
57
|
+
- verb: get
|
|
58
|
+
objectRef.resource: pods
|
|
59
|
+
requestObject.spec.containers.securityContext.privileged: true
|
|
60
|
+
|
|
61
|
+
k8s-privilege-escalation-workload:
|
|
62
|
+
date: "2026-10-12"
|
|
63
|
+
title: "Kubernetes workload allows privilege escalation or adds dangerous capabilities"
|
|
64
|
+
description: >-
|
|
65
|
+
A pod or workload controller is created or updated with
|
|
66
|
+
allowPrivilegeEscalation true or a container capability that breaks
|
|
67
|
+
isolation (SYS_ADMIN, NET_ADMIN, SYS_PTRACE, SYS_MODULE, ALL).
|
|
68
|
+
AttackMap found this in ${locations} (rule ${rule_id}).
|
|
69
|
+
logsource: {product: kubernetes, service: audit}
|
|
70
|
+
fields_required: [verb, objectRef.resource, objectRef.namespace, user.username, requestObject.spec.containers.securityContext.allowPrivilegeEscalation, requestObject.spec.containers.securityContext.capabilities.add]
|
|
71
|
+
detection:
|
|
72
|
+
selection_write:
|
|
73
|
+
verb: [create, update, patch]
|
|
74
|
+
objectRef.resource: [pods, deployments, daemonsets, statefulsets, replicasets, replicationcontrollers, jobs, cronjobs]
|
|
75
|
+
esc_flag:
|
|
76
|
+
- requestObject.spec.containers.securityContext.allowPrivilegeEscalation: true
|
|
77
|
+
- requestObject.spec.initContainers.securityContext.allowPrivilegeEscalation: true
|
|
78
|
+
- requestObject.spec.ephemeralContainers.securityContext.allowPrivilegeEscalation: true
|
|
79
|
+
- requestObject.spec.template.spec.containers.securityContext.allowPrivilegeEscalation: true
|
|
80
|
+
- requestObject.spec.template.spec.initContainers.securityContext.allowPrivilegeEscalation: true
|
|
81
|
+
- requestObject.spec.template.spec.ephemeralContainers.securityContext.allowPrivilegeEscalation: true
|
|
82
|
+
- requestObject.spec.jobTemplate.spec.template.spec.containers.securityContext.allowPrivilegeEscalation: true
|
|
83
|
+
- requestObject.spec.jobTemplate.spec.template.spec.initContainers.securityContext.allowPrivilegeEscalation: true
|
|
84
|
+
- requestObject.spec.jobTemplate.spec.template.spec.ephemeralContainers.securityContext.allowPrivilegeEscalation: true
|
|
85
|
+
esc_cap:
|
|
86
|
+
- requestObject.spec.containers.securityContext.capabilities.add: [SYS_ADMIN, NET_ADMIN, SYS_PTRACE, SYS_MODULE, DAC_READ_SEARCH, ALL]
|
|
87
|
+
- requestObject.spec.initContainers.securityContext.capabilities.add: [SYS_ADMIN, NET_ADMIN, SYS_PTRACE, SYS_MODULE, DAC_READ_SEARCH, ALL]
|
|
88
|
+
- requestObject.spec.ephemeralContainers.securityContext.capabilities.add: [SYS_ADMIN, NET_ADMIN, SYS_PTRACE, SYS_MODULE, DAC_READ_SEARCH, ALL]
|
|
89
|
+
- requestObject.spec.template.spec.containers.securityContext.capabilities.add: [SYS_ADMIN, NET_ADMIN, SYS_PTRACE, SYS_MODULE, DAC_READ_SEARCH, ALL]
|
|
90
|
+
- requestObject.spec.template.spec.initContainers.securityContext.capabilities.add: [SYS_ADMIN, NET_ADMIN, SYS_PTRACE, SYS_MODULE, DAC_READ_SEARCH, ALL]
|
|
91
|
+
- requestObject.spec.template.spec.ephemeralContainers.securityContext.capabilities.add: [SYS_ADMIN, NET_ADMIN, SYS_PTRACE, SYS_MODULE, DAC_READ_SEARCH, ALL]
|
|
92
|
+
- requestObject.spec.jobTemplate.spec.template.spec.containers.securityContext.capabilities.add: [SYS_ADMIN, NET_ADMIN, SYS_PTRACE, SYS_MODULE, DAC_READ_SEARCH, ALL]
|
|
93
|
+
- requestObject.spec.jobTemplate.spec.template.spec.initContainers.securityContext.capabilities.add: [SYS_ADMIN, NET_ADMIN, SYS_PTRACE, SYS_MODULE, DAC_READ_SEARCH, ALL]
|
|
94
|
+
- requestObject.spec.jobTemplate.spec.template.spec.ephemeralContainers.securityContext.capabilities.add: [SYS_ADMIN, NET_ADMIN, SYS_PTRACE, SYS_MODULE, DAC_READ_SEARCH, ALL]
|
|
95
|
+
condition: selection_write and 1 of esc_*
|
|
96
|
+
falsepositives:
|
|
97
|
+
- Network and storage agents that need NET_ADMIN or SYS_ADMIN (exclude their namespaces)
|
|
98
|
+
level: medium
|
|
99
|
+
test_events:
|
|
100
|
+
positive:
|
|
101
|
+
- verb: create
|
|
102
|
+
objectRef.resource: pods
|
|
103
|
+
requestObject.spec.containers.securityContext.capabilities.add: SYS_ADMIN
|
|
104
|
+
negative:
|
|
105
|
+
- verb: create
|
|
106
|
+
objectRef.resource: pods
|
|
107
|
+
requestObject.spec.containers.securityContext.capabilities.add: NET_BIND_SERVICE
|
|
108
|
+
|
|
109
|
+
k8s-host-access-workload:
|
|
110
|
+
date: "2026-10-12"
|
|
111
|
+
title: "Kubernetes workload mounts a host path or shares a host namespace"
|
|
112
|
+
description: >-
|
|
113
|
+
A pod or workload controller is created or updated with a hostPath
|
|
114
|
+
volume or hostNetwork / hostPID / hostIPC, which give the container
|
|
115
|
+
the node's files or namespaces. AttackMap found this in ${locations}
|
|
116
|
+
(rule ${rule_id}).
|
|
117
|
+
logsource: {product: kubernetes, service: audit}
|
|
118
|
+
fields_required: [verb, objectRef.resource, objectRef.namespace, user.username, requestObject.spec.volumes.hostPath.path, requestObject.spec.hostNetwork, requestObject.spec.hostPID, requestObject.spec.hostIPC]
|
|
119
|
+
detection:
|
|
120
|
+
selection_write:
|
|
121
|
+
verb: [create, update, patch]
|
|
122
|
+
objectRef.resource: [pods, deployments, daemonsets, statefulsets, replicasets, replicationcontrollers, jobs, cronjobs]
|
|
123
|
+
host_path:
|
|
124
|
+
- requestObject.spec.volumes.hostPath.path|startswith: /
|
|
125
|
+
- requestObject.spec.template.spec.volumes.hostPath.path|startswith: /
|
|
126
|
+
- requestObject.spec.jobTemplate.spec.template.spec.volumes.hostPath.path|startswith: /
|
|
127
|
+
host_namespace:
|
|
128
|
+
- requestObject.spec.hostNetwork: true
|
|
129
|
+
- requestObject.spec.hostPID: true
|
|
130
|
+
- requestObject.spec.hostIPC: true
|
|
131
|
+
- requestObject.spec.template.spec.hostNetwork: true
|
|
132
|
+
- requestObject.spec.template.spec.hostPID: true
|
|
133
|
+
- requestObject.spec.template.spec.hostIPC: true
|
|
134
|
+
- requestObject.spec.jobTemplate.spec.template.spec.hostNetwork: true
|
|
135
|
+
- requestObject.spec.jobTemplate.spec.template.spec.hostPID: true
|
|
136
|
+
- requestObject.spec.jobTemplate.spec.template.spec.hostIPC: true
|
|
137
|
+
condition: selection_write and 1 of host_*
|
|
138
|
+
falsepositives:
|
|
139
|
+
- Node agents (log shippers, CNI, node exporters) that read the host by design; exclude their namespaces
|
|
140
|
+
level: high
|
|
141
|
+
test_events:
|
|
142
|
+
positive:
|
|
143
|
+
- verb: create
|
|
144
|
+
objectRef.resource: daemonsets
|
|
145
|
+
requestObject.spec.template.spec.volumes.hostPath.path: /var/run/docker.sock
|
|
146
|
+
- verb: patch
|
|
147
|
+
objectRef.resource: deployments
|
|
148
|
+
requestObject.spec.template.spec.hostNetwork: true
|
|
149
|
+
negative:
|
|
150
|
+
- verb: create
|
|
151
|
+
objectRef.resource: deployments
|
|
152
|
+
requestObject.spec.template.spec.hostNetwork: false
|
|
153
|
+
- verb: delete
|
|
154
|
+
objectRef.resource: daemonsets
|
|
155
|
+
requestObject.spec.template.spec.volumes.hostPath.path: /var/log
|
|
156
|
+
|
|
157
|
+
k8s-exposed-service:
|
|
158
|
+
date: "2026-10-12"
|
|
159
|
+
title: "Kubernetes Service exposed outside the cluster"
|
|
160
|
+
description: >-
|
|
161
|
+
A Service is created or changed to type LoadBalancer or NodePort,
|
|
162
|
+
which publishes it outside the cluster. AttackMap found exposed
|
|
163
|
+
services in ${locations} (rule ${rule_id}).
|
|
164
|
+
logsource: {product: kubernetes, service: audit}
|
|
165
|
+
fields_required: [verb, objectRef.resource, objectRef.namespace, objectRef.name, user.username, requestObject.spec.type]
|
|
166
|
+
detection:
|
|
167
|
+
selection:
|
|
168
|
+
verb: [create, update, patch]
|
|
169
|
+
objectRef.resource: services
|
|
170
|
+
requestObject.spec.type: [LoadBalancer, NodePort]
|
|
171
|
+
condition: selection
|
|
172
|
+
falsepositives:
|
|
173
|
+
- Ingress controllers and intended public services; exclude them by namespace and name
|
|
174
|
+
level: low
|
|
175
|
+
test_events:
|
|
176
|
+
positive:
|
|
177
|
+
- verb: create
|
|
178
|
+
objectRef.resource: services
|
|
179
|
+
requestObject.spec.type: LoadBalancer
|
|
180
|
+
negative:
|
|
181
|
+
- verb: create
|
|
182
|
+
objectRef.resource: services
|
|
183
|
+
requestObject.spec.type: ClusterIP
|
|
184
|
+
|
|
185
|
+
k8s-rbac-wildcard-grant:
|
|
186
|
+
date: "2026-10-12"
|
|
187
|
+
title: "Kubernetes Role or ClusterRole granting wildcard verbs or resources"
|
|
188
|
+
description: >-
|
|
189
|
+
A Role or ClusterRole is created or changed with "*" in its verbs or
|
|
190
|
+
resources. AttackMap found wildcard RBAC rules in ${locations} (rule
|
|
191
|
+
${rule_id}).
|
|
192
|
+
logsource: {product: kubernetes, service: audit}
|
|
193
|
+
fields_required: [verb, objectRef.resource, objectRef.name, user.username, requestObject.rules.verbs, requestObject.rules.resources]
|
|
194
|
+
detection:
|
|
195
|
+
selection_write:
|
|
196
|
+
verb: [create, update, patch]
|
|
197
|
+
objectRef.resource: [roles, clusterroles]
|
|
198
|
+
wildcard_verbs:
|
|
199
|
+
requestObject.rules.verbs|re: ^\*$
|
|
200
|
+
wildcard_resources:
|
|
201
|
+
requestObject.rules.resources|re: ^\*$
|
|
202
|
+
condition: selection_write and 1 of wildcard_*
|
|
203
|
+
falsepositives:
|
|
204
|
+
- The built-in cluster-admin and admin roles when the cluster is bootstrapped or upgraded (user system:apiserver)
|
|
205
|
+
level: high
|
|
206
|
+
test_events:
|
|
207
|
+
positive:
|
|
208
|
+
- verb: create
|
|
209
|
+
objectRef.resource: clusterroles
|
|
210
|
+
user.username: alice
|
|
211
|
+
requestObject.rules.verbs: "*"
|
|
212
|
+
negative:
|
|
213
|
+
- verb: create
|
|
214
|
+
objectRef.resource: clusterroles
|
|
215
|
+
user.username: alice
|
|
216
|
+
requestObject.rules.verbs: get
|
|
217
|
+
|
|
218
|
+
k8s-rbac-escalation-grant:
|
|
219
|
+
date: "2026-10-12"
|
|
220
|
+
title: "Kubernetes RBAC grant of escalate, bind or impersonate"
|
|
221
|
+
description: >-
|
|
222
|
+
A Role or ClusterRole is created or changed to allow escalate, bind or
|
|
223
|
+
impersonate, the verbs that let a subject grant itself more rights.
|
|
224
|
+
AttackMap found such rules in ${locations} (rule ${rule_id}).
|
|
225
|
+
logsource: {product: kubernetes, service: audit}
|
|
226
|
+
fields_required: [verb, objectRef.resource, objectRef.name, user.username, requestObject.rules.verbs]
|
|
227
|
+
detection:
|
|
228
|
+
selection:
|
|
229
|
+
verb: [create, update, patch]
|
|
230
|
+
objectRef.resource: [roles, clusterroles]
|
|
231
|
+
requestObject.rules.verbs: [escalate, bind, impersonate]
|
|
232
|
+
condition: selection
|
|
233
|
+
falsepositives:
|
|
234
|
+
- Cluster bootstrap and operators that manage RBAC (user system:apiserver, OLM)
|
|
235
|
+
level: high
|
|
236
|
+
test_events:
|
|
237
|
+
positive:
|
|
238
|
+
- verb: patch
|
|
239
|
+
objectRef.resource: roles
|
|
240
|
+
requestObject.rules.verbs: impersonate
|
|
241
|
+
negative:
|
|
242
|
+
- verb: patch
|
|
243
|
+
objectRef.resource: roles
|
|
244
|
+
requestObject.rules.verbs: list
|
|
245
|
+
|
|
246
|
+
k8s-pod-exec:
|
|
247
|
+
date: "2026-10-12"
|
|
248
|
+
title: "Service account opens an exec or attach session in a Kubernetes pod"
|
|
249
|
+
description: >-
|
|
250
|
+
A service account (not a person) opens an exec or attach session in a
|
|
251
|
+
pod (pods/exec, pods/attach). kubectl 1.30 and later exec over
|
|
252
|
+
WebSocket, which reaches the API server as a GET and is recorded with
|
|
253
|
+
verb get; older clients use create. AttackMap found RBAC rules that grant
|
|
254
|
+
this broadly in ${locations} (rule ${rule_id}); with them, a stolen
|
|
255
|
+
service-account token runs commands in other workloads. Workloads
|
|
256
|
+
rarely exec into each other, so this is a strong signal.
|
|
257
|
+
logsource: {product: kubernetes, service: audit}
|
|
258
|
+
fields_required: [verb, objectRef.resource, objectRef.subresource, objectRef.namespace, objectRef.name, user.username]
|
|
259
|
+
detection:
|
|
260
|
+
selection:
|
|
261
|
+
verb: [create, get]
|
|
262
|
+
objectRef.resource: pods
|
|
263
|
+
objectRef.subresource: [exec, attach]
|
|
264
|
+
user.username|startswith: "system:serviceaccount:"
|
|
265
|
+
condition: selection
|
|
266
|
+
falsepositives:
|
|
267
|
+
- CI/CD or debugging tools that exec through a service account (exclude them by name)
|
|
268
|
+
level: high
|
|
269
|
+
test_events:
|
|
270
|
+
positive:
|
|
271
|
+
- verb: create
|
|
272
|
+
objectRef.resource: pods
|
|
273
|
+
objectRef.subresource: exec
|
|
274
|
+
user.username: system:serviceaccount:web:default
|
|
275
|
+
- verb: get
|
|
276
|
+
objectRef.resource: pods
|
|
277
|
+
objectRef.subresource: exec
|
|
278
|
+
user.username: system:serviceaccount:ci:runner
|
|
279
|
+
negative:
|
|
280
|
+
- verb: create
|
|
281
|
+
objectRef.resource: pods
|
|
282
|
+
objectRef.subresource: exec
|
|
283
|
+
user.username: alice@example.com
|
|
284
|
+
- verb: get
|
|
285
|
+
objectRef.resource: pods
|
|
286
|
+
objectRef.subresource: log
|
|
287
|
+
user.username: system:serviceaccount:web:default
|
|
288
|
+
|
|
289
|
+
k8s-cluster-admin-binding:
|
|
290
|
+
date: "2026-10-12"
|
|
291
|
+
title: "Kubernetes binding to the cluster-admin role"
|
|
292
|
+
description: >-
|
|
293
|
+
A RoleBinding or ClusterRoleBinding to cluster-admin is created or
|
|
294
|
+
changed. AttackMap found cluster-admin bindings in ${locations} (rule
|
|
295
|
+
${rule_id}).
|
|
296
|
+
logsource: {product: kubernetes, service: audit}
|
|
297
|
+
fields_required: [verb, objectRef.resource, objectRef.name, user.username, requestObject.roleRef.name, requestObject.subjects.name]
|
|
298
|
+
detection:
|
|
299
|
+
selection:
|
|
300
|
+
verb: [create, update, patch]
|
|
301
|
+
objectRef.resource: [clusterrolebindings, rolebindings]
|
|
302
|
+
requestObject.roleRef.name: cluster-admin
|
|
303
|
+
condition: selection
|
|
304
|
+
falsepositives:
|
|
305
|
+
- Cluster bootstrap (user system:apiserver) and managed-cluster admin setup
|
|
306
|
+
level: high
|
|
307
|
+
test_events:
|
|
308
|
+
positive:
|
|
309
|
+
- verb: create
|
|
310
|
+
objectRef.resource: clusterrolebindings
|
|
311
|
+
requestObject.roleRef.name: cluster-admin
|
|
312
|
+
negative:
|
|
313
|
+
- verb: create
|
|
314
|
+
objectRef.resource: clusterrolebindings
|
|
315
|
+
requestObject.roleRef.name: view
|
|
316
|
+
|
|
317
|
+
k8s-secret-enumeration:
|
|
318
|
+
date: "2026-10-12"
|
|
319
|
+
title: "Kubernetes secrets listed or watched by a non-system user"
|
|
320
|
+
description: >-
|
|
321
|
+
A list or watch of secrets by a user or service account outside the
|
|
322
|
+
control plane. AttackMap found roles granting broad secret access in
|
|
323
|
+
${locations} (rule ${rule_id}); bulk reads are how a stolen token is
|
|
324
|
+
turned into every credential in the namespace or cluster.
|
|
325
|
+
logsource: {product: kubernetes, service: audit}
|
|
326
|
+
fields_required: [verb, objectRef.resource, objectRef.namespace, user.username]
|
|
327
|
+
detection:
|
|
328
|
+
selection:
|
|
329
|
+
verb: [list, watch]
|
|
330
|
+
objectRef.resource: secrets
|
|
331
|
+
filter_control_plane:
|
|
332
|
+
user.username|startswith: ["system:kube-", "system:node:", "system:serviceaccount:kube-system:"]
|
|
333
|
+
condition: selection and not filter_control_plane
|
|
334
|
+
falsepositives:
|
|
335
|
+
- Operators and controllers that cache secrets (cert-manager, external-secrets, Helm); exclude their service accounts
|
|
336
|
+
level: low
|
|
337
|
+
test_events:
|
|
338
|
+
positive:
|
|
339
|
+
- verb: list
|
|
340
|
+
objectRef.resource: secrets
|
|
341
|
+
user.username: system:serviceaccount:web:default
|
|
342
|
+
negative:
|
|
343
|
+
- verb: list
|
|
344
|
+
objectRef.resource: secrets
|
|
345
|
+
user.username: system:kube-controller-manager
|
|
346
|
+
- verb: get
|
|
347
|
+
objectRef.resource: configmaps
|
|
348
|
+
user.username: alice
|
|
349
|
+
|
|
350
|
+
aws-security-group-open-ingress:
|
|
351
|
+
date: "2026-10-12"
|
|
352
|
+
title: "AWS security group opened to the whole internet"
|
|
353
|
+
description: >-
|
|
354
|
+
An ingress rule allowing 0.0.0.0/0 or ::/0 is added to a security
|
|
355
|
+
group. AttackMap found publicly reachable network rules in
|
|
356
|
+
${locations} (rule ${rule_id}).
|
|
357
|
+
logsource: {product: aws, service: cloudtrail}
|
|
358
|
+
fields_required: [eventSource, eventName, userIdentity.arn, sourceIPAddress, requestParameters.groupId, requestParameters.ipPermissions.items.ipRanges.items.cidrIp, requestParameters.ipPermissions.items.ipv6Ranges.items.cidrIpv6]
|
|
359
|
+
detection:
|
|
360
|
+
selection:
|
|
361
|
+
eventSource: ec2.amazonaws.com
|
|
362
|
+
eventName: AuthorizeSecurityGroupIngress
|
|
363
|
+
open_v4:
|
|
364
|
+
requestParameters.ipPermissions.items.ipRanges.items.cidrIp: 0.0.0.0/0
|
|
365
|
+
open_v6:
|
|
366
|
+
requestParameters.ipPermissions.items.ipv6Ranges.items.cidrIpv6: "::/0"
|
|
367
|
+
condition: selection and 1 of open_*
|
|
368
|
+
falsepositives:
|
|
369
|
+
- Load balancer security groups that are public by design (ports 80/443)
|
|
370
|
+
level: medium
|
|
371
|
+
test_events:
|
|
372
|
+
positive:
|
|
373
|
+
- eventSource: ec2.amazonaws.com
|
|
374
|
+
eventName: AuthorizeSecurityGroupIngress
|
|
375
|
+
requestParameters.ipPermissions.items.ipRanges.items.cidrIp: 0.0.0.0/0
|
|
376
|
+
negative:
|
|
377
|
+
- eventSource: ec2.amazonaws.com
|
|
378
|
+
eventName: AuthorizeSecurityGroupIngress
|
|
379
|
+
requestParameters.ipPermissions.items.ipRanges.items.cidrIp: 10.0.0.0/8
|
|
380
|
+
|
|
381
|
+
aws-rds-publicly-accessible:
|
|
382
|
+
date: "2026-10-12"
|
|
383
|
+
title: "AWS RDS database made publicly accessible"
|
|
384
|
+
description: >-
|
|
385
|
+
An RDS instance or cluster is created or modified with
|
|
386
|
+
PubliclyAccessible true. AttackMap found publicly accessible databases
|
|
387
|
+
in ${locations} (rule ${rule_id}).
|
|
388
|
+
logsource: {product: aws, service: cloudtrail}
|
|
389
|
+
fields_required: [eventSource, eventName, userIdentity.arn, requestParameters.dBInstanceIdentifier, requestParameters.publiclyAccessible]
|
|
390
|
+
detection:
|
|
391
|
+
selection:
|
|
392
|
+
eventSource: rds.amazonaws.com
|
|
393
|
+
eventName: [CreateDBInstance, ModifyDBInstance, CreateDBCluster, ModifyDBCluster, RestoreDBInstanceFromDBSnapshot]
|
|
394
|
+
requestParameters.publiclyAccessible: true
|
|
395
|
+
condition: selection
|
|
396
|
+
falsepositives:
|
|
397
|
+
- Databases deliberately public behind other controls (rare; document them)
|
|
398
|
+
level: high
|
|
399
|
+
test_events:
|
|
400
|
+
positive:
|
|
401
|
+
- eventSource: rds.amazonaws.com
|
|
402
|
+
eventName: ModifyDBInstance
|
|
403
|
+
requestParameters.publiclyAccessible: true
|
|
404
|
+
negative:
|
|
405
|
+
- eventSource: rds.amazonaws.com
|
|
406
|
+
eventName: ModifyDBInstance
|
|
407
|
+
requestParameters.publiclyAccessible: false
|
|
408
|
+
|
|
409
|
+
aws-instance-public-ip:
|
|
410
|
+
date: "2026-10-12"
|
|
411
|
+
title: "AWS EC2 instance launched with a public IP address"
|
|
412
|
+
description: >-
|
|
413
|
+
RunInstances with a network interface that associates a public IP.
|
|
414
|
+
AttackMap found instances with public addresses in ${locations} (rule
|
|
415
|
+
${rule_id}).
|
|
416
|
+
logsource: {product: aws, service: cloudtrail}
|
|
417
|
+
fields_required: [eventSource, eventName, userIdentity.arn, requestParameters.networkInterfaceSet.items.associatePublicIpAddress]
|
|
418
|
+
detection:
|
|
419
|
+
selection:
|
|
420
|
+
eventSource: ec2.amazonaws.com
|
|
421
|
+
eventName: RunInstances
|
|
422
|
+
requestParameters.networkInterfaceSet.items.associatePublicIpAddress: true
|
|
423
|
+
condition: selection
|
|
424
|
+
falsepositives:
|
|
425
|
+
- Bastion hosts and public-facing instances by design; exclude by subnet or tag
|
|
426
|
+
level: low
|
|
427
|
+
test_events:
|
|
428
|
+
positive:
|
|
429
|
+
- eventSource: ec2.amazonaws.com
|
|
430
|
+
eventName: RunInstances
|
|
431
|
+
requestParameters.networkInterfaceSet.items.associatePublicIpAddress: true
|
|
432
|
+
negative:
|
|
433
|
+
- eventSource: ec2.amazonaws.com
|
|
434
|
+
eventName: RunInstances
|
|
435
|
+
requestParameters.networkInterfaceSet.items.associatePublicIpAddress: false
|
|
436
|
+
|
|
437
|
+
aws-s3-made-public:
|
|
438
|
+
date: "2026-10-12"
|
|
439
|
+
title: "AWS S3 Block Public Access weakened or public ACL applied"
|
|
440
|
+
description: >-
|
|
441
|
+
A bucket's (or the account's) Block Public Access configuration is
|
|
442
|
+
deleted or set with any of its four protections off, or a public
|
|
443
|
+
canned ACL is applied. AttackMap found publicly readable storage in
|
|
444
|
+
${locations} (rule ${rule_id}).
|
|
445
|
+
logsource: {product: aws, service: cloudtrail}
|
|
446
|
+
fields_required: [eventSource, eventName, userIdentity.arn, requestParameters.bucketName, requestParameters.x-amz-acl, requestParameters.PublicAccessBlockConfiguration.BlockPublicAcls, requestParameters.PublicAccessBlockConfiguration.IgnorePublicAcls, requestParameters.PublicAccessBlockConfiguration.BlockPublicPolicy, requestParameters.PublicAccessBlockConfiguration.RestrictPublicBuckets]
|
|
447
|
+
detection:
|
|
448
|
+
selection_s3:
|
|
449
|
+
eventSource: [s3.amazonaws.com, s3-control.amazonaws.com]
|
|
450
|
+
block_removed:
|
|
451
|
+
eventName: [DeleteBucketPublicAccessBlock, DeleteAccountPublicAccessBlock, DeletePublicAccessBlock]
|
|
452
|
+
block_weakened:
|
|
453
|
+
- eventName: [PutBucketPublicAccessBlock, PutAccountPublicAccessBlock, PutPublicAccessBlock]
|
|
454
|
+
requestParameters.PublicAccessBlockConfiguration.BlockPublicAcls: false
|
|
455
|
+
- eventName: [PutBucketPublicAccessBlock, PutAccountPublicAccessBlock, PutPublicAccessBlock]
|
|
456
|
+
requestParameters.PublicAccessBlockConfiguration.IgnorePublicAcls: false
|
|
457
|
+
- eventName: [PutBucketPublicAccessBlock, PutAccountPublicAccessBlock, PutPublicAccessBlock]
|
|
458
|
+
requestParameters.PublicAccessBlockConfiguration.BlockPublicPolicy: false
|
|
459
|
+
- eventName: [PutBucketPublicAccessBlock, PutAccountPublicAccessBlock, PutPublicAccessBlock]
|
|
460
|
+
requestParameters.PublicAccessBlockConfiguration.RestrictPublicBuckets: false
|
|
461
|
+
public_acl:
|
|
462
|
+
eventName: [PutBucketAcl, PutObjectAcl, CreateBucket]
|
|
463
|
+
requestParameters.x-amz-acl: [public-read, public-read-write]
|
|
464
|
+
condition: selection_s3 and (block_removed or block_weakened or public_acl)
|
|
465
|
+
falsepositives:
|
|
466
|
+
- Static-website buckets that are public by design
|
|
467
|
+
level: high
|
|
468
|
+
test_events:
|
|
469
|
+
positive:
|
|
470
|
+
- eventSource: s3.amazonaws.com
|
|
471
|
+
eventName: PutBucketAcl
|
|
472
|
+
requestParameters.x-amz-acl: public-read
|
|
473
|
+
- eventSource: s3.amazonaws.com
|
|
474
|
+
eventName: DeleteBucketPublicAccessBlock
|
|
475
|
+
- eventSource: s3.amazonaws.com
|
|
476
|
+
eventName: PutBucketPublicAccessBlock
|
|
477
|
+
requestParameters.PublicAccessBlockConfiguration.BlockPublicAcls: true
|
|
478
|
+
requestParameters.PublicAccessBlockConfiguration.IgnorePublicAcls: true
|
|
479
|
+
requestParameters.PublicAccessBlockConfiguration.BlockPublicPolicy: false
|
|
480
|
+
requestParameters.PublicAccessBlockConfiguration.RestrictPublicBuckets: true
|
|
481
|
+
negative:
|
|
482
|
+
- eventSource: s3.amazonaws.com
|
|
483
|
+
eventName: PutBucketAcl
|
|
484
|
+
requestParameters.x-amz-acl: private
|
|
485
|
+
- eventSource: s3.amazonaws.com
|
|
486
|
+
eventName: PutBucketPublicAccessBlock
|
|
487
|
+
requestParameters.PublicAccessBlockConfiguration.BlockPublicAcls: true
|
|
488
|
+
requestParameters.PublicAccessBlockConfiguration.IgnorePublicAcls: true
|
|
489
|
+
requestParameters.PublicAccessBlockConfiguration.BlockPublicPolicy: true
|
|
490
|
+
requestParameters.PublicAccessBlockConfiguration.RestrictPublicBuckets: true
|
|
491
|
+
|
|
492
|
+
aws-s3-public-policy:
|
|
493
|
+
date: "2026-10-12"
|
|
494
|
+
title: "AWS S3 bucket policy with a wildcard principal"
|
|
495
|
+
description: >-
|
|
496
|
+
PutBucketPolicy with a statement whose principal is "*" (anyone).
|
|
497
|
+
AttackMap found publicly readable storage in ${locations} (rule
|
|
498
|
+
${rule_id}). Flattened policy fields can't tie the principal to its
|
|
499
|
+
statement's effect, so a Deny statement with Principal "*" (the
|
|
500
|
+
common aws:SecureTransport guard) also matches; check the Effect.
|
|
501
|
+
logsource: {product: aws, service: cloudtrail}
|
|
502
|
+
fields_required: [eventSource, eventName, userIdentity.arn, requestParameters.bucketName, requestParameters.bucketPolicy.Statement.Principal, requestParameters.bucketPolicy.Statement.Principal.AWS, requestParameters.bucketPolicy.Statement.Effect]
|
|
503
|
+
detection:
|
|
504
|
+
selection:
|
|
505
|
+
eventSource: s3.amazonaws.com
|
|
506
|
+
eventName: PutBucketPolicy
|
|
507
|
+
wildcard_principal:
|
|
508
|
+
- requestParameters.bucketPolicy.Statement.Principal|re: ^\*$
|
|
509
|
+
- requestParameters.bucketPolicy.Statement.Principal.AWS|re: ^\*$
|
|
510
|
+
condition: selection and wildcard_principal
|
|
511
|
+
falsepositives:
|
|
512
|
+
- Deny statements with Principal "*" (for example requiring TLS); review the policy's Allow statements
|
|
513
|
+
- Static-website buckets that are public by design
|
|
514
|
+
level: medium
|
|
515
|
+
test_events:
|
|
516
|
+
positive:
|
|
517
|
+
- eventSource: s3.amazonaws.com
|
|
518
|
+
eventName: PutBucketPolicy
|
|
519
|
+
requestParameters.bucketPolicy.Statement.Principal: "*"
|
|
520
|
+
requestParameters.bucketPolicy.Statement.Effect: Allow
|
|
521
|
+
negative:
|
|
522
|
+
- eventSource: s3.amazonaws.com
|
|
523
|
+
eventName: PutBucketPolicy
|
|
524
|
+
requestParameters.bucketPolicy.Statement.Principal.AWS: arn:aws:iam::123456789012:role/reader
|
|
525
|
+
|
|
526
|
+
aws-eks-public-endpoint:
|
|
527
|
+
date: "2026-10-12"
|
|
528
|
+
title: "AWS EKS cluster API endpoint made public"
|
|
529
|
+
description: >-
|
|
530
|
+
An EKS cluster is reconfigured with endpointPublicAccess true, or
|
|
531
|
+
created without endpointPublicAccess false (the API endpoint is public
|
|
532
|
+
by default). AttackMap found public cluster endpoints in ${locations}
|
|
533
|
+
(rule ${rule_id}).
|
|
534
|
+
logsource: {product: aws, service: cloudtrail}
|
|
535
|
+
fields_required: [eventSource, eventName, userIdentity.arn, requestParameters.name, requestParameters.resourcesVpcConfig.endpointPublicAccess, requestParameters.resourcesVpcConfig.publicAccessCidrs]
|
|
536
|
+
detection:
|
|
537
|
+
selection_eks:
|
|
538
|
+
eventSource: eks.amazonaws.com
|
|
539
|
+
made_public:
|
|
540
|
+
eventName: [CreateCluster, UpdateClusterConfig]
|
|
541
|
+
requestParameters.resourcesVpcConfig.endpointPublicAccess: true
|
|
542
|
+
public_by_default:
|
|
543
|
+
eventName: CreateCluster
|
|
544
|
+
requestParameters.resourcesVpcConfig.endpointPublicAccess: null
|
|
545
|
+
condition: selection_eks and (made_public or public_by_default)
|
|
546
|
+
falsepositives:
|
|
547
|
+
- Clusters with a public endpoint restricted by publicAccessCidrs; check the CIDRs
|
|
548
|
+
level: medium
|
|
549
|
+
test_events:
|
|
550
|
+
positive:
|
|
551
|
+
- eventSource: eks.amazonaws.com
|
|
552
|
+
eventName: UpdateClusterConfig
|
|
553
|
+
requestParameters.resourcesVpcConfig.endpointPublicAccess: true
|
|
554
|
+
- eventSource: eks.amazonaws.com
|
|
555
|
+
eventName: CreateCluster
|
|
556
|
+
requestParameters.name: main
|
|
557
|
+
negative:
|
|
558
|
+
- eventSource: eks.amazonaws.com
|
|
559
|
+
eventName: UpdateClusterConfig
|
|
560
|
+
requestParameters.resourcesVpcConfig.endpointPublicAccess: false
|
|
561
|
+
- eventSource: eks.amazonaws.com
|
|
562
|
+
eventName: CreateCluster
|
|
563
|
+
requestParameters.resourcesVpcConfig.endpointPublicAccess: false
|
|
564
|
+
- eventSource: eks.amazonaws.com
|
|
565
|
+
eventName: UpdateClusterConfig
|
|
566
|
+
requestParameters.name: main
|
|
567
|
+
|
|
568
|
+
data:
|
|
569
|
+
# Rule id -> the templates that detect it. `platforms` limits a template to
|
|
570
|
+
# records on those platforms; `resource_types` (AWS) to Terraform resource
|
|
571
|
+
# types (the part of `resource` before the first dot). Kinds with no entry
|
|
572
|
+
# (unencrypted storage, unpinned images, Dockerfile issues, missing
|
|
573
|
+
# security contexts, ...) have no control-plane event to watch; the
|
|
574
|
+
# coverage table shows them as not covered. Launch templates and launch
|
|
575
|
+
# configurations are left out: their public-IP flag isn't in RunInstances'
|
|
576
|
+
# request, and their own create calls aren't mapped yet.
|
|
577
|
+
mapping:
|
|
578
|
+
privileged-container:
|
|
579
|
+
- {template: k8s-privileged-workload, platforms: [kubernetes, helm]}
|
|
580
|
+
privilege-escalation-allowed:
|
|
581
|
+
- {template: k8s-privilege-escalation-workload, platforms: [kubernetes, helm]}
|
|
582
|
+
dangerous-capability:
|
|
583
|
+
- {template: k8s-privilege-escalation-workload, platforms: [kubernetes, helm]}
|
|
584
|
+
host-path-mount:
|
|
585
|
+
- {template: k8s-host-access-workload, platforms: [kubernetes, helm]}
|
|
586
|
+
host-namespace-shared:
|
|
587
|
+
- {template: k8s-host-access-workload, platforms: [kubernetes, helm]}
|
|
588
|
+
exposed-service:
|
|
589
|
+
- {template: k8s-exposed-service, platforms: [kubernetes, helm]}
|
|
590
|
+
rbac-wildcard:
|
|
591
|
+
- {template: k8s-rbac-wildcard-grant, platforms: [kubernetes, helm, terraform]}
|
|
592
|
+
- {template: k8s-pod-exec, platforms: [kubernetes, helm, terraform]}
|
|
593
|
+
rbac-escalation:
|
|
594
|
+
- {template: k8s-rbac-escalation-grant, platforms: [kubernetes, helm, terraform]}
|
|
595
|
+
- {template: k8s-pod-exec, platforms: [kubernetes, helm, terraform]}
|
|
596
|
+
cluster-admin-binding:
|
|
597
|
+
- {template: k8s-cluster-admin-binding, platforms: [kubernetes, helm, terraform]}
|
|
598
|
+
rbac-secret-access:
|
|
599
|
+
- {template: k8s-secret-enumeration, platforms: [kubernetes, helm, terraform]}
|
|
600
|
+
public-network-access:
|
|
601
|
+
- {template: aws-security-group-open-ingress, platforms: [aws], resource_types: [aws_security_group, aws_security_group_rule, aws_vpc_security_group_ingress_rule]}
|
|
602
|
+
- {template: aws-rds-publicly-accessible, platforms: [aws], resource_types: [aws_db_instance, aws_rds_cluster, aws_rds_cluster_instance]}
|
|
603
|
+
- {template: aws-instance-public-ip, platforms: [aws], resource_types: [aws_instance]}
|
|
604
|
+
public-data-access:
|
|
605
|
+
- {template: aws-s3-made-public, platforms: [aws], resource_types: [aws_s3_bucket, aws_s3_bucket_acl, aws_s3_bucket_public_access_block, aws_s3_account_public_access_block]}
|
|
606
|
+
- {template: aws-s3-public-policy, platforms: [aws], resource_types: [aws_s3_bucket, aws_s3_bucket_policy]}
|
|
607
|
+
- {template: aws-rds-publicly-accessible, platforms: [aws], resource_types: [aws_db_instance, aws_rds_cluster, aws_rds_cluster_instance]}
|
|
608
|
+
public-cluster-endpoint:
|
|
609
|
+
- {template: aws-eks-public-endpoint, platforms: [aws], resource_types: [aws_eks_cluster]}
|