Detection rules › Elastic

Suspicious Instance Metadata Service (IMDS) API Request

Status
production
Severity
medium
Time window
9m
Group by
host.id, process.executable
Author
Elastic
Source
github.com/elastic/detection-rules

This rule identifies various tools/scripts performing network activities attempting to access the cloud service provider's instance metadata service (IMDS) API endpoint, which can be used to retrieve sensitive instance-specific information such as instance ID, public IP address, and even temporary security credentials if roles are assumed by that instance.

MITRE ATT&CK coverage

Telemetry coverage

ProviderRecord / event type
SysmonEvent ID 3: Network connection

Rule body

[metadata]
creation_date = "2026/05/22"
integration = ["endpoint"]
maturity = "production"
updated_date = "2026/05/22"

[rule]
author = ["Elastic"]
description = """
This rule identifies various tools/scripts performing network activities attempting to access the cloud service provider's
instance metadata service (IMDS) API endpoint, which can be used to retrieve sensitive instance-specific information such
as instance ID, public IP address, and even temporary security credentials if roles are assumed by that instance.
"""
from = "now-9m"
index = ["logs-endpoint.events.network-*"]
language = "kuery"
license = "Elastic License v2"
name = "Suspicious Instance Metadata Service (IMDS) API Request"
note = """## Triage and analysis

> **Disclaimer**:
> This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs.

### Investigating Suspicious Instance Metadata Service (IMDS) API Request

This alert flags command interpreters, scripting engines, or unusual binaries on a host trying to contact the local instance metadata service, a high-value source of instance details and temporary cloud credentials. A common attacker pattern is gaining code execution on a Linux or Windows VM, then using curl, PowerShell, or a script dropped in a temporary directory to query 169.254.169.254 and harvest the attached role credentials for follow-on cloud access.

### Possible investigation steps

- Review the full execution chain and any referenced script or binary contents to determine whether the metadata request came from approved bootstrap or agent activity versus an interactive shell, web application process, scheduled job, or recently dropped file.
- Identify the initiating account, session context, and trigger for the execution to separate expected automation from hands-on-keyboard behavior, especially if it followed a remote login, privilege escalation, or exploitation event.
- Correlate the host and timeframe with cloud control-plane telemetry to confirm whether instance role credentials or managed identity tokens were later used against storage, secrets, IAM, subscription, or other sensitive APIs.
- Examine nearby endpoint activity for follow-on collection and staging behavior such as writing token output to disk, exporting environment data, invoking cloud CLIs or SDKs, compressing files, or making outbound connections to unfamiliar destinations.
- Validate with the asset owner whether the workload legitimately requires IMDS access, and if the activity is unexplained, contain the host and rotate any exposed instance profile or managed identity credentials.

### False positive analysis

- A legitimate bootstrap, login, or scheduled administration script may use curl, PowerShell, or Python to query 169.254.169.254 for instance ID, public IP, or temporary role credentials during normal configuration, so verify the command line, parent process, and execution timing match expected startup or maintenance activity from an approved path.
- An approved in-house application or service may call IMDS through a shell or runtime such as java, node, or python to obtain instance-specific settings or cloud authentication at runtime, so confirm the binary or script is expected on that host and that the requests align with normal service startup behavior rather than a new interactive session or a temporary-directory executable.

### Response and remediation

- Isolate the affected instance or host from the network or move it to a containment security group, terminate active remote sessions, and preserve volatile evidence such as the running process tree, shell history, temporary scripts, and recent command output tied to the 169.254.169.254 request.
- Revoke or rotate any cloud role credentials, API keys, tokens, and application secrets that may have been exposed through IMDS, and detach or replace the instance profile or managed identity if it granted access beyond the workload’s normal needs.
- Remove the attacker’s foothold by deleting the script or binary that queried IMDS and eradicating associated persistence such as cron jobs, systemd services, rc.local changes, scheduled tasks, Run keys, WMI event subscriptions, launch agents, or modified shell startup files.
- Restore the system from a known-good image or snapshot when integrity is in doubt, validate that no unauthorized users, SSH keys, services, or startup items remain, and reset credentials for any local, domain, or service accounts used on the host.
- Escalate to incident response and cloud security immediately if IMDS returned temporary role credentials, if that role was used from unfamiliar IP addresses or regions, or if similar metadata queries are observed on multiple hosts, and expand scoping to all resources reachable by the compromised role.
- Harden the environment by enforcing IMDSv2 or the cloud provider’s strongest metadata protections, disabling metadata access where unnecessary, blocking local access to 169.254.169.254 for unapproved processes, reducing instance-role privileges, and preventing script execution from temporary or user-writable directories.
"""
references = [
    "https://hackingthe.cloud/aws/general-knowledge/intro_metadata_service/",
    "https://www.wiz.io/blog/imds-anomaly-hunting-zero-day",
]
risk_score = 47
rule_id = "ad02da2f-443d-454c-a12e-d9e6c65831ff"
severity = "medium"
tags = [
    "Domain: Endpoint",
    "Domain: Cloud",
    "OS: Linux",
    "OS: Windows",
    "OS: macOS",
    "Use Case: Threat Detection",
    "Tactic: Credential Access",
    "Tactic: Discovery",
    "Data Source: Elastic Defend",
    "Resources: Investigation Guide",
]
timestamp_override = "event.ingested"
type = "new_terms"
query = '''
event.category:"network" and host.os.type:("windows" or "macos" or "linux") and
 (destination.ip:"169.254.169.254" or destination.address :"169.254.169.254") and destination.port:"80" and (
  process.name:(
    "bash" or "dash" or "sh" or "tcsh" or "tclsh" or "wish" or "csh" or "zsh" or "ksh" or "fish" or
    "mksh" or "busybox" or "ld.so" or "ld-linux-x86-64.so.2" or "bun" or "bun.exe" or "node" or "node.exe" or
    "nodejs" or "deno" or "deno.exe" or "java" or "java.exe" or "env" or "timeout" or "setsid" or "flock" or
    "curl" or "curl.exe" or "wget" or "wget.exe" or "powershell.exe" or "cmd.exe" or "pwsh.exe" or
    "wscript.exe" or  "cscript.exe" or "regsvr32.exe" or "mshta.exe" or "rundll32.exe" or "vbc.exe" or
    "msbuild.exe" or "wmic.exe" or "cmstp.exe" or "RegAsm.exe" or "installutil.exe" or "RegSvcs.exe" or
    "msxsl.exe" or "xwizard.exe" or "csc.exe" or "pwsh" or python* or perl* or ruby* or lua* or php* or
    "terminal" or "osascript" or "nohup" or .* or "javaw" or "javaw.exe"
  ) or
  process.executable:(
    ./* or /boot/* or /dev/shm/* or /run/* or /var/run/* or /tmp/* or /var/tmp/* or /var/www/* or
    /home/*/* or /root/* or /private/var/tmp/* or /var/folders/* or /Users/Shared/* or /var/root/*
  )
) and
not (
  (
    host.os.type:"macos" and
    process.name:"node"
  ) or
  (
    process.name:"Cursor Helper (Plugin)" and
    process.code_signature.trusted:true and
    process.code_signature.signing_id:"com.github.Electron.helper"
  ) or
  (
    process.name:"Code Helper (Plugin)" and
    process.code_signature.trusted:true and
    process.code_signature.signing_id:("com.microsoft.VSCode.helper" or "com.github.Electron.helper")
  ) or
  process.executable:/vscode/vscode-server/bin/linux-x64/*/node
)
'''

[[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 = "T1016"
name = "System Network Configuration Discovery"
reference = "https://attack.mitre.org/techniques/T1016/"

[[rule.threat.technique]]
id = "T1082"
name = "System Information Discovery"
reference = "https://attack.mitre.org/techniques/T1082/"

[[rule.threat.technique]]
id = "T1580"
name = "Cloud Infrastructure Discovery"
reference = "https://attack.mitre.org/techniques/T1580/"

[rule.threat.tactic]
id = "TA0007"
name = "Discovery"
reference = "https://attack.mitre.org/tactics/TA0007/"

[rule.new_terms]
field = "new_terms_fields"
value = ["host.id", "process.executable"]

[[rule.new_terms.history_window_start]]
field = "history_window_start"
value = "now-7d"

Stages and Predicates

Stage 1: new_terms

event.category:"network" and host.os.type:("windows" or "macos" or "linux") and
 (destination.ip:"169.254.169.254" or destination.address :"169.254.169.254") and destination.port:"80" and (
  process.name:(
    "bash" or "dash" or "sh" or "tcsh" or "tclsh" or "wish" or "csh" or "zsh" or "ksh" or "fish" or
    "mksh" or "busybox" or "ld.so" or "ld-linux-x86-64.so.2" or "bun" or "bun.exe" or "node" or "node.exe" or
    "nodejs" or "deno" or "deno.exe" or "java" or "java.exe" or "env" or "timeout" or "setsid" or "flock" or
    "curl" or "curl.exe" or "wget" or "wget.exe" or "powershell.exe" or "cmd.exe" or "pwsh.exe" or
    "wscript.exe" or  "cscript.exe" or "regsvr32.exe" or "mshta.exe" or "rundll32.exe" or "vbc.exe" or
    "msbuild.exe" or "wmic.exe" or "cmstp.exe" or "RegAsm.exe" or "installutil.exe" or "RegSvcs.exe" or
    "msxsl.exe" or "xwizard.exe" or "csc.exe" or "pwsh" or python* or perl* or ruby* or lua* or php* or
    "terminal" or "osascript" or "nohup" or .* or "javaw" or "javaw.exe"
  ) or
  process.executable:(
    ./* or /boot/* or /dev/shm/* or /run/* or /var/run/* or /tmp/* or /var/tmp/* or /var/www/* or
    /home/*/* or /root/* or /private/var/tmp/* or /var/folders/* or /Users/Shared/* or /var/root/*
  )
) and
not (
  (
    host.os.type:"macos" and
    process.name:"node"
  ) or
  (
    process.name:"Cursor Helper (Plugin)" and
    process.code_signature.trusted:true and
    process.code_signature.signing_id:"com.github.Electron.helper"
  ) or
  (
    process.name:"Code Helper (Plugin)" and
    process.code_signature.trusted:true and
    process.code_signature.signing_id:("com.microsoft.VSCode.helper" or "com.github.Electron.helper")
  ) or
  process.executable:/vscode/vscode-server/bin/linux-x64/*/node
)

Exclusions

The rule actively suppresses these predicates.

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
destination.addresseq
  • 169.254.169.254
field:"destination.address" kind:eq value:"169.254.169.254"
destination.ipeq
  • 169.254.169.254 corpus 3 (elastic 2, kusto 1)
field:"dest_ip" kind:eq value:"169.254.169.254"
destination.porteq
  • 80 corpus 11 (sigma 6, elastic 3, kusto 2)
field:"DestinationPort" kind:eq value:"80"
event.categoryeq
  • network corpus 19 (elastic 19)
field:"event.category" kind:eq value:"network"
process.executablewildcard
  • ./* corpus 26 (elastic 26)
  • /Users/Shared/* corpus 8 (elastic 7, sigma 1)
  • /boot/* corpus 28 (elastic 28)
  • /dev/shm/* corpus 53 (elastic 51, sigma 2)
  • /home/*/* corpus 23 (elastic 23)
  • /private/var/tmp/* corpus 2 (elastic 2)
  • /root/* corpus 13 (elastic 13)
  • /run/* corpus 20 (elastic 20)
  • /tmp/* corpus 58 (elastic 56, sigma 2)
  • /var/folders/* corpus 3 (elastic 3)
  • /var/root/* corpus 5 (elastic 5)
  • /var/run/* corpus 23 (elastic 23)
  • /var/tmp/* corpus 56 (elastic 55, sigma 1)
  • /var/www/* corpus 11 (elastic 11)
field:"Image" kind:wildcard
process.nameeq
  • RegAsm.exe corpus 26 (elastic 24, splunk 2)
  • RegSvcs.exe corpus 23 (elastic 21, splunk 2)
  • bash corpus 12 (elastic 12)
  • bun corpus 2 (elastic 2)
  • bun.exe
  • busybox corpus 12 (elastic 12)
  • cmd.exe corpus 121 (elastic 92, splunk 29)
  • cmstp.exe corpus 25 (elastic 25)
  • csc.exe corpus 12 (elastic 11, splunk 1)
  • cscript.exe corpus 67 (elastic 65, splunk 2)
  • csh corpus 7 (elastic 7)
  • curl corpus 29 (elastic 24, splunk 5)
  • curl.exe corpus 34 (elastic 31, splunk 3)
  • dash corpus 9 (elastic 9)
  • deno corpus 4 (elastic 4)
  • deno.exe corpus 3 (elastic 3)
  • env corpus 4 (elastic 4)
  • fish corpus 7 (elastic 7)
  • flock corpus 3 (elastic 3)
  • installutil.exe corpus 37 (elastic 32, splunk 5)
  • java corpus 5 (elastic 5)
  • java.exe corpus 2 (elastic 1, splunk 1)
  • javaw
  • javaw.exe corpus 9 (elastic 9)
  • ksh corpus 8 (elastic 8)
  • ld-linux-x86-64.so.2 corpus 3 (elastic 3)
  • ld.so corpus 3 (elastic 3)
  • mksh corpus 3 (elastic 3)
  • msbuild.exe corpus 39 (elastic 36, splunk 3)
  • mshta.exe corpus 84 (elastic 79, splunk 5)
  • msxsl.exe corpus 23 (elastic 22, splunk 1)
  • node corpus 25 (elastic 25)
  • node.exe corpus 6 (elastic 6)
  • nodejs corpus 3 (elastic 3)
  • nohup corpus 4 (elastic 4)
  • osascript corpus 46 (elastic 46)
  • powershell.exe corpus 184 (elastic 140, splunk 44)
  • pwsh corpus 4 (elastic 4)
  • pwsh.exe corpus 77 (elastic 48, splunk 29)
  • regsvr32.exe corpus 73 (elastic 68, splunk 5)
  • rundll32.exe corpus 126 (elastic 100, splunk 26)
  • setsid corpus 4 (elastic 4)
  • sh corpus 12 (elastic 11, splunk 1)
  • tclsh corpus 3 (elastic 3)
  • tcsh corpus 8 (elastic 8)
  • terminal
  • timeout corpus 3 (elastic 3)
  • vbc.exe corpus 9 (elastic 8, splunk 1)
  • wget corpus 19 (elastic 18, splunk 1)
  • wget.exe corpus 6 (elastic 6)
  • wish corpus 3 (elastic 3)
  • wmic.exe corpus 66 (elastic 39, splunk 27)
  • wscript.exe corpus 83 (elastic 82, splunk 1)
  • xwizard.exe corpus 16 (elastic 16)
  • zsh corpus 12 (elastic 12)
field:"process_name" kind:eq
process.namewildcard
  • .* corpus 38 (elastic 38)
  • lua* corpus 30 (elastic 30)
  • perl* corpus 36 (elastic 36)
  • php* corpus 28 (elastic 28)
  • python* corpus 71 (elastic 71)
  • ruby* corpus 36 (elastic 36)
field:"process_name" kind:wildcard