Detection rules › Elastic
Kubernetes Pod Exec Cloud Instance Metadata Access
Detects Kubernetes pod exec sessions whose decoded command line references cloud instance metadata endpoints or equivalent hostnames and paths. Workloads that reach the link-local metadata IP, AWS IMDS paths, GCP computeMetadata, Azure IMDS token routes, or encoded variants are often attempting to harvest role credentials, tokens, or instance attributes from the underlying node or hypervisor boundary. That behavior is high risk in multi-tenant and regulated environments because it can expose short-lived cloud credentials to code running inside a container. The rule classifies a coarse cloud target label and whether the string looks like credential retrieval versus lighter reconnaissance.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Execution | |
| Credential Access |
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Kubernetes | get-pods-exec: get pods/exec |
| Kubernetes | create-pods-exec: create pods/exec |
Rules detecting the same action
These rules filter on the same operation.
- Kubernetes Multi-Resource Discovery (Elastic)
- Kubernetes Pod Exec Potential Reverse Shell (Elastic)
- Kubernetes Pod Exec Sensitive File or Credential Path Access (Elastic)
- Kubernetes Pod Exec with Curl or Wget to HTTPS (Elastic)
- Kubernetes Unusual Decision by User Agent (Elastic)
- port-forward (Falco)
- Unauthorized Kubernetes Pod Execution (Panther)
- Unauthorized Kubernetes Pod Execution (Panther)
Rule body
[metadata]
creation_date = "2026/04/23"
integration = ["kubernetes"]
maturity = "production"
updated_date = "2026/04/23"
[rule]
author = ["Elastic"]
description = """
Detects Kubernetes pod exec sessions whose decoded command line references cloud instance metadata endpoints or
equivalent hostnames and paths. Workloads that reach the link-local metadata IP, AWS IMDS paths, GCP computeMetadata,
Azure IMDS token routes, or encoded variants are often attempting to harvest role credentials, tokens, or instance
attributes from the underlying node or hypervisor boundary. That behavior is high risk in multi-tenant and regulated
environments because it can expose short-lived cloud credentials to code running inside a container. The rule
classifies a coarse cloud target label and whether the string looks like credential retrieval versus lighter
reconnaissance.
"""
from = "now-6m"
interval = "5m"
language = "esql"
license = "Elastic License v2"
name = "Kubernetes Pod Exec Cloud Instance Metadata Access"
note = """## Triage and analysis
### Investigating Kubernetes Pod Exec Cloud Instance Metadata Access
This alert fires when an audited exec requestURI, after URL decoding and command reconstruction, matches patterns
associated with instance metadata services across AWS, GCP, and Azure. Use it to catch interactive or scripted access
from inside a pod to metadata surfaces that should usually be blocked by network policy or not needed by application
code.
### Possible investigation steps
- Confirm the Kubernetes identity that performed exec: user name, groups, impersonation, source IP, and user agent.
- Map the pod and namespace to a workload owner, image digest, and entrypoint; determine whether the container should
ever call metadata endpoints.
- Inspect Esql.cloud_target and Esql.is_credential_theft in the alert document and expand the timeline for the same
identity for secret reads, IAM changes, or data egress.
- Correlate with cloud audit logs on the node identity or instance profile for STS or token issuance around the event
time.
### False positive analysis
- Break-glass debugging from platform engineers may include curl to 169.254.169.254; validate change tickets and
bastion use.
- Misconfigured agents or bootstrap scripts in bespoke images can touch metadata during startup; baseline approved
images and tune exclusions narrowly.
### Response and remediation
- If unauthorized, terminate the session, isolate the workload, revoke or rotate instance and workload credentials that
could have been read, and tighten RBAC on pods exec plus network policies that deny link-local metadata from pods.
"""
references = [
"https://attack.mitre.org/techniques/T1552/005/",
"https://hardenedsecurity.io/blog/aws-imds-vulnerabilities-and-mitigations/",
]
risk_score = 73
rule_id = "a8e7d6c5-b4a3-2918-0f9e-8d7c6b5a4032"
severity = "high"
tags = [
"Data Source: Kubernetes",
"Domain: Kubernetes",
"Domain: Cloud",
"Use Case: Threat Detection",
"Tactic: Credential Access",
"Tactic: Execution",
"Resources: Investigation Guide",
]
timestamp_override = "event.ingested"
type = "esql"
query = '''
FROM logs-kubernetes.audit_logs-* metadata _id, _index, _version
| WHERE kubernetes.audit.objectRef.subresource == "exec"
AND kubernetes.audit.requestURI LIKE "*command=*"
| EVAL decoded_uri = URL_DECODE(kubernetes.audit.requestURI)
| GROK decoded_uri "%{DATA}/exec\\?%{DATA:raw_commands}&(?:container|stdin|stdout|stderr)=%{GREEDYDATA}"
| EVAL command = REPLACE(raw_commands, "command=", "")
| EVAL command = REPLACE(command, "&", " ")
| EVAL Esql.executed_command = REPLACE(command, "\\+", " ")
| WHERE Esql.executed_command IS NOT NULL
AND Esql.executed_command RLIKE """.*(169\.254\.169\.254|2852039166|0xa9fea9fe|/latest/api/token|/latest/meta-data|/latest/user-data|/latest/dynamic/instance-identity|computeMetadata/v1|metadata\.google\.internal|metadata/identity/oauth2/token|metadata/instance).*"""
| EVAL Esql.cloud_target = CASE(
Esql.executed_command RLIKE """.*(169\.254\.169\.254|2852039166|0xa9fea9fe|/latest/meta-data|/latest/api/token|/latest/user-data|/latest/dynamic).*""", "AWS_IMDS",
Esql.executed_command RLIKE """.*(computeMetadata/v1|metadata\.google\.internal).*""", "GCP_METADATA",
Esql.executed_command RLIKE """.*metadata/identity/oauth2/token.*""", "AZURE_IMDS",
"UNKNOWN"
)
| EVAL Esql.is_credential_theft = CASE(
Esql.executed_command RLIKE """.*(security-credentials|/api/token|oauth2/token|service-accounts/.*/token).*""", "yes",
"recon"
)
| KEEP *
'''
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1552"
name = "Unsecured Credentials"
reference = "https://attack.mitre.org/techniques/T1552/"
[[rule.threat.technique.subtechnique]]
id = "T1552.005"
name = "Cloud Instance Metadata API"
reference = "https://attack.mitre.org/techniques/T1552/005/"
[rule.threat.tactic]
id = "TA0006"
name = "Credential Access"
reference = "https://attack.mitre.org/tactics/TA0006/"
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1609"
name = "Container Administration Command"
reference = "https://attack.mitre.org/techniques/T1609/"
[rule.threat.tactic]
id = "TA0002"
name = "Execution"
reference = "https://attack.mitre.org/tactics/TA0002/"
Stages and Predicates
Stage 1: from
FROM logs-kubernetes.audit_logs-* metadata _id, _index, _version
Stage 2: where
| WHERE kubernetes.audit.objectRef.subresource == "exec"
AND kubernetes.audit.requestURI LIKE "*command=*"
Stage 3: eval
| EVAL decoded_uri = URL_DECODE(kubernetes.audit.requestURI)
Stage 4: grok
| GROK decoded_uri "%{DATA}/exec\\?%{DATA:raw_commands}&(?:container|stdin|stdout|stderr)=%{GREEDYDATA}"
Stage 5: eval
| EVAL command = REPLACE(raw_commands, "command=", "")
Stage 6: eval
| EVAL command = REPLACE(command, "&", " ")
Stage 7: eval
| EVAL Esql.executed_command = REPLACE(command, "\\+", " ")
Stage 8: where
| WHERE Esql.executed_command IS NOT NULL
AND Esql.executed_command RLIKE """.*(169\.254\.169\.254|2852039166|0xa9fea9fe|/latest/api/token|/latest/meta-data|/latest/user-data|/latest/dynamic/instance-identity|computeMetadata/v1|metadata\.google\.internal|metadata/identity/oauth2/token|metadata/instance).*"""
Stage 9: eval
| EVAL Esql.cloud_target = CASE(
Esql.executed_command RLIKE """.*(169\.254\.169\.254|2852039166|0xa9fea9fe|/latest/meta-data|/latest/api/token|/latest/user-data|/latest/dynamic).*""", "AWS_IMDS",
Esql.executed_command RLIKE """.*(computeMetadata/v1|metadata\.google\.internal).*""", "GCP_METADATA",
Esql.executed_command RLIKE """.*metadata/identity/oauth2/token.*""", "AZURE_IMDS",
"UNKNOWN"
)
Esql.cloud_target =Esql.executed_command RLIKE """.*(169\.254\.169\.254|2852039166|0xa9fea9fe|/latest/meta-data|/latest/api/token|/latest/user-data|/latest/dynamic).*""""AWS_IMDS"Esql.executed_command RLIKE """.*(computeMetadata/v1|metadata\.google\.internal).*""""GCP_METADATA"Esql.executed_command RLIKE """.*metadata/identity/oauth2/token.*""""AZURE_IMDS""UNKNOWN"Stage 10: eval
| EVAL Esql.is_credential_theft = CASE(
Esql.executed_command RLIKE """.*(security-credentials|/api/token|oauth2/token|service-accounts/.*/token).*""", "yes",
"recon"
)
Esql.is_credential_theft =Esql.executed_command RLIKE """.*(security-credentials|/api/token|oauth2/token|service-accounts/.*/token).*""""yes""recon"Stage 11: keep
| KEEP *
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Esql.executed_command | is_not_null | field:"Esql.executed_command" kind:is_not_null | |
Esql.executed_command | regex_match |
| field:"Esql.executed_command" kind:regex_match value:".*(169.254.169.254|2852039166|0xa9fea9fe|/latest/api/token|/latest/meta-data|/latest/user-data|/latest/dynamic/instance-identity|computeMetadata/v1|metadata.google.internal|metadata/identity/oauth2/token|metadata/instance).*" |
kubernetes.audit.objectRef.subresource | eq |
| field:"kubernetes.audit.objectRef.subresource" kind:eq value:"exec" |
kubernetes.audit.requestURI | wildcard |
| field:"kubernetes.audit.requestURI" kind:wildcard value:"*command=*" |
Output fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
* | KEEP * |