Kubernetes Pod Exec with Curl or Wget to HTTPS

Detects pod or attach exec API calls where the decoded request query implies curl or wget fetching an https URL. Attackers with permission to exec into workloads often run one-liners to stage tooling, pull scripts or binaries, or exfiltrate data over HTTPS—activity that should be rare compared to shells, debuggers, or expected health checks. The rule decodes the audit requestURI, reconstructs a readable command string from repeated command parameters, and applies noise filters for common cluster health and OIDC/JWKS endpoints so benign automation is less likely to alert.

Elastic rule (View on GitHub)

  1[metadata]
  2creation_date = "2026/04/23"
  3integration = ["kubernetes"]
  4maturity = "production"
  5min_stack_comments = "URL_DECODE was added to ES|QL in 9.2.0 and is not available on 8.19; 9.3.0 is the lowest supported 9.x release."
  6min_stack_version = "9.3.0"
  7updated_date = "2026/09/22"
  8
  9[rule]
 10author = ["Elastic"]
 11description = """
 12Detects pod or attach exec API calls where the decoded request query implies curl or wget fetching an
 13https URL. Attackers with permission to exec into workloads often run one-liners to stage tooling, pull
 14scripts or binaries, or exfiltrate data over HTTPS—activity that should be rare compared to shells, debuggers, or
 15expected health checks. The rule decodes the audit requestURI, reconstructs a readable command string from
 16repeated command parameters, and applies noise filters for common cluster health and OIDC/JWKS endpoints so
 17benign automation is less likely to alert.
 18"""
 19from = "now-6m"
 20interval = "5m"
 21language = "esql"
 22license = "Elastic License v2"
 23name = "Kubernetes Pod Exec with Curl or Wget to HTTPS"
 24note = """## Triage and analysis
 25
 26### Investigating Kubernetes Pod Exec with Curl or Wget to HTTPS
 27
 28Kubernetes audit logs record exec (and similar attach) calls on requestURI, including URL-encoded
 29command segments. This rule URL-decodes the URI, extracts the query portion into a single string, and 
 30flags curl or wget combined with https, excluding several common health, localhost, and OIDC/JWKS patterns.
 31
 32### Possible investigation steps
 33
 34- Confirm who may exec into the target namespace: review kubernetes.audit.user.username, groups, impersonation, and
 35  source.ip / user_agent.original (kubectl, CI, webhooks).
 36- Map the pod (kubernetes.audit.objectRef.name) and workload owner; retrieve the decoded URI from
 37  Esql.decoded_uri and the reconstructed Esql.executed_command in the alert.
 38- Search for adjacent audit events from the same identity: secret reads, additional execs, RBAC changes, or anonymous
 39  access.
 40- If malicious, revoke credentials used for exec, review RoleBindings for **`pods/exec`**, and inspect the pod
 41  filesystem or snapshot for dropped artifacts.
 42
 43### False positive analysis
 44
 45- Approved runbooks or support sessions may use kubectl exec with curl/wget to test egress or download vendor tools;
 46  document break-glass identities and tune exclusions.
 47- Some cluster components use HTTPS to **kubernetes.default.svc** or **.well-known** endpoints; the rule attempts to
 48  filter those—expand the exclusion list if your platform uses additional first-party URLs.
 49
 50### Response and remediation
 51
 52- Rotate any secrets accessible from the pod, cordon or delete the workload if compromised, and tighten RBAC so only
 53  required principals retain **`pods/exec`** on sensitive namespaces.
 54"""
 55references = [
 56    "https://attack.mitre.org/techniques/T1609/",
 57    "https://attack.mitre.org/techniques/T1105/",
 58]
 59risk_score = 73
 60rule_id = "c9d4e8f1-2a3b-4c5d-8e9f-0a1b2c3d4e5f"
 61severity = "high"
 62tags = [
 63    "Data Source: Kubernetes",
 64    "Data Source: Kubernetes API Server Audit Logs",
 65    "Domain: Kubernetes",
 66    "Platform: Kubernetes",
 67    "Use Case: Threat Detection",
 68    "Tactic: Execution",
 69    "Tactic: Command and Control",
 70    "Resources: Investigation Guide",
 71    "Noise: Unknown",
 72    "Performance: Normal",
 73    "Profile: Recommended",
 74    "Threat: Download Tool Abuse",
 75    "Rule Type: ES|QL",
 76    "Domain: Containers",
 77    "Domain: Cloud",
 78]
 79timestamp_override = "event.ingested"
 80type = "esql"
 81query = '''
 82FROM logs-kubernetes.audit_logs-* metadata _id, _index, _version
 83| WHERE kubernetes.audit.objectRef.subresource == "exec"
 84  AND kubernetes.audit.requestURI LIKE "*command=*"
 85| EVAL Esql.decoded_uri = URL_DECODE(kubernetes.audit.requestURI)
 86| GROK Esql.decoded_uri "%{DATA}/exec\\?%{DATA:raw_commands}&(?:container|stdin|stdout|stderr)=%{GREEDYDATA}"
 87| EVAL command = REPLACE(raw_commands, "command=", "")
 88| EVAL command = REPLACE(command, "&", " ")
 89| EVAL Esql.executed_command = REPLACE(command, "\\+", " ")
 90| WHERE Esql.executed_command IS NOT NULL 
 91  AND Esql.executed_command RLIKE """.*(curl.*https|wget.*https).*"""
 92  AND NOT Esql.executed_command RLIKE """.*(/api/v1/health|/healthz|/readyz|/livez|127\.0\.0\.1|localhost|/openid/v1/jwks|/openid-connect/certs|/.well-known/openid-configuration|/.well-known/jwks\.json|kubernetes\.default\.svc).*"""
 93| KEEP Esql.*, user.name, user_agent.original, event.*, source.ip, kubernetes.audit.*, _id, _version, _index, data_stream.namespace
 94'''
 95
 96[[rule.threat]]
 97framework = "MITRE ATT&CK"
 98
 99[[rule.threat.technique]]
100id = "T1609"
101name = "Container Administration Command"
102reference = "https://attack.mitre.org/techniques/T1609/"
103
104[rule.threat.tactic]
105id = "TA0002"
106name = "Execution"
107reference = "https://attack.mitre.org/tactics/TA0002/"
108
109[[rule.threat]]
110framework = "MITRE ATT&CK"
111
112[[rule.threat.technique]]
113id = "T1105"
114name = "Ingress Tool Transfer"
115reference = "https://attack.mitre.org/techniques/T1105/"
116
117[rule.threat.tactic]
118id = "TA0011"
119name = "Command and Control"
120reference = "https://attack.mitre.org/tactics/TA0011/"

Triage and analysis

Investigating Kubernetes Pod Exec with Curl or Wget to HTTPS

Kubernetes audit logs record exec (and similar attach) calls on requestURI, including URL-encoded command segments. This rule URL-decodes the URI, extracts the query portion into a single string, and flags curl or wget combined with https, excluding several common health, localhost, and OIDC/JWKS patterns.

Possible investigation steps

  • Confirm who may exec into the target namespace: review kubernetes.audit.user.username, groups, impersonation, and source.ip / user_agent.original (kubectl, CI, webhooks).
  • Map the pod (kubernetes.audit.objectRef.name) and workload owner; retrieve the decoded URI from Esql.decoded_uri and the reconstructed Esql.executed_command in the alert.
  • Search for adjacent audit events from the same identity: secret reads, additional execs, RBAC changes, or anonymous access.
  • If malicious, revoke credentials used for exec, review RoleBindings for pods/exec, and inspect the pod filesystem or snapshot for dropped artifacts.

False positive analysis

  • Approved runbooks or support sessions may use kubectl exec with curl/wget to test egress or download vendor tools; document break-glass identities and tune exclusions.
  • Some cluster components use HTTPS to kubernetes.default.svc or .well-known endpoints; the rule attempts to filter those—expand the exclusion list if your platform uses additional first-party URLs.

Response and remediation

  • Rotate any secrets accessible from the pod, cordon or delete the workload if compromised, and tighten RBAC so only required principals retain pods/exec on sensitive namespaces.

References

Related rules

to-top