Package Runtime Secret File Access Followed by IMDS Request
Description
Identifies a Python, Node.js, Bun, Deno, Ruby, PHP or Perl runtime, or a binary executing from a package install location, that opens a developer secret (SSH keys, package registry tokens, source control credentials or AI coding assistant credentials) and then connects to a cloud instance metadata service (IMDS) endpoint within one minute. This sequence matches credential stealers delivered through compromised packages, such as the malicious LiteLLM PyPI releases, while cloud provider credential files are excluded because legitimate cloud SDK credential chains read them before falling back to IMDS.
Query · eql
sequence by process.entity_id with maxspan=1m
[file where event.action == "open" and host.os.type in ("macos", "windows") and
file.path like~ (
/* SSH private keys */
"/Users/*/.ssh/id_*", "?:\\Users\\*\\.ssh\\id_*",
/* Package registry, source control and secrets manager tokens */
"/Users/*/.npmrc", "?:\\Users\\*\\.npmrc",
"/Users/*/.pypirc", "?:\\Users\\*\\.pypirc",
"/Users/*/.git-credentials", "?:\\Users\\*\\.git-credentials",
"/Users/*/.config/git/credentials", "?:\\Users\\*\\.config\\git\\credentials",
"/Users/*/.config/gh/hosts.yml", "?:\\Users\\*\\AppData\\Roaming\\GitHub CLI\\hosts.yml",
"/Users/*/.vault-token", "?:\\Users\\*\\.vault-token",
"/Users/*/.terraform.d/credentials.tfrc.json", "?:\\Users\\*\\AppData\\Roaming\\terraform.d\\credentials.tfrc.json",
/* Additional package registry and AI/ML platform tokens */
"/Users/*/.yarnrc.yml", "?:\\Users\\*\\.yarnrc.yml",
"/Users/*/.gem/credentials", "?:\\Users\\*\\.gem\\credentials",
"/Users/*/.cargo/credentials.toml", "?:\\Users\\*\\.cargo\\credentials.toml",
"/Users/*/.composer/auth.json", "/Users/*/.config/composer/auth.json", "?:\\Users\\*\\AppData\\Roaming\\Composer\\auth.json",
"/Users/*/.cache/huggingface/token", "/Users/*/.huggingface/token", "?:\\Users\\*\\.cache\\huggingface\\token", "?:\\Users\\*\\.huggingface\\token",
"/Users/*/.config/github-copilot/apps.json", "/Users/*/.config/github-copilot/hosts.json",
"?:\\Users\\*\\AppData\\Local\\github-copilot\\apps.json", "?:\\Users\\*\\AppData\\Local\\github-copilot\\hosts.json",
"/Users/*/.ollama/id_ed25519", "?:\\Users\\*\\.ollama\\id_ed25519",
/* AI coding assistant credentials */
"/Users/*/.claude/.credentials.json", "?:\\Users\\*\\.claude\\.credentials.json",
"/Users/*/.codex/auth.json", "?:\\Users\\*\\.codex\\auth.json",
"/Users/*/.codex/.credentials.json", "?:\\Users\\*\\.codex\\.credentials.json",
"/Users/*/.codex/secrets/*.age", "?:\\Users\\*\\.codex\\secrets\\*.age",
"/Users/*/.gemini/oauth_creds.json", "?:\\Users\\*\\.gemini\\oauth_creds.json",
"/Users/*/.gemini/gemini-credentials.json", "?:\\Users\\*\\.gemini\\gemini-credentials.json",
"/Users/*/.gemini/mcp-oauth-tokens.json", "?:\\Users\\*\\.gemini\\mcp-oauth-tokens.json",
"/Users/*/.gemini/a2a-oauth-tokens.json", "?:\\Users\\*\\.gemini\\a2a-oauth-tokens.json",
"/Users/*/.qwen/oauth_creds.json", "?:\\Users\\*\\.qwen\\oauth_creds.json",
"/Users/*/.qwen/mcp-oauth-tokens.json", "?:\\Users\\*\\.qwen\\mcp-oauth-tokens.json",
"/Users/*/.aws/sso/cache/kiro-auth-token.json", "?:\\Users\\*\\.aws\\sso\\cache\\kiro-auth-token.json",
"/Users/*/.local/share/opencode/auth.json", "?:\\Users\\*\\.local\\share\\opencode\\auth.json",
"/Users/*/.local/share/opencode/mcp-auth.json", "?:\\Users\\*\\.local\\share\\opencode\\mcp-auth.json",
"/Users/*/.local/share/amp/secrets.json", "?:\\Users\\*\\.local\\share\\amp\\secrets.json",
"/Users/*/.augment/session.json", "?:\\Users\\*\\.augment\\session.json",
"/Users/*/.kimi/credentials/kimi-code.json", "?:\\Users\\*\\.kimi\\credentials\\kimi-code.json",
"/Users/*/.cursor/auth.json", "?:\\Users\\*\\.cursor\\auth.json",
"/Users/*/.pi/agent/auth.json", "?:\\Users\\*\\.pi\\agent\\auth.json",
"/Users/*/.config/goose/secrets.yaml", "?:\\Users\\*\\AppData\\Roaming\\Block\\goose\\config\\secrets.yaml",
"/Users/*/.config/muse/auth.json", "?:\\Users\\*\\.config\\muse\\auth.json",
"/Users/*/.local/share/devin/credentials.toml", "?:\\Users\\*\\AppData\\Roaming\\devin\\credentials.toml",
"/Users/*/.openclaw/credentials/oauth.json", "?:\\Users\\*\\.openclaw\\credentials\\oauth.json",
"/Users/*/.openclaw/agents/*/agent/auth-profiles.json", "?:\\Users\\*\\.openclaw\\agents\\*\\agent\\auth-profiles.json",
"/Users/*/.openclaw/agents/*/agent/auth.json", "?:\\Users\\*\\.openclaw\\agents\\*\\agent\\auth.json"
) and
/* SSH public keys are not secrets and are routinely read by SSH and cloud tooling */
not file.path like~ "*.pub" and
/* Package ecosystem runtimes or binaries executing from package install locations */
(
process.name like~ ("python*", "node", "node.exe", "nodejs", "bun", "bun.exe", "deno", "deno.exe", "ruby*", "php*", "perl*") or
process.executable like~ ("*/site-packages/*", "*/dist-packages/*", "*/node_modules/*", "*\\site-packages\\*", "*\\node_modules\\*",
"*/.venv/*", "*/venv/*", "*\\.venv\\*", "*\\venv\\*")
)
]
[network where
cidrmatch(destination.ip, "169.254.169.254/32", "169.254.170.2/32", "169.254.170.23/32", "100.100.100.200/32", "fd00:ec2::254/128", "fd00:ec2::23/128") and
destination.port == 80 and event.action == "connection_attempted" and host.os.type in ("macos", "windows")
]
Implementation guide
This rule requires data from Elastic Defend with file and network event collection enabled.
Elastic Defend only generates file open events on macOS and Windows, and only for paths in its event-on-access file
path list. That list is delivered through the Elastic Defend global configuration artifact and can be extended per
policy with the advanced.events.event_on_access.file_paths advanced setting. Credential paths in this rule that are
not yet present in the deployed global configuration only match after they are added to that setting. On Windows,
repeated access events for the same path are deduplicated for one hour by default.
This rule is scoped to macOS and Windows because Elastic Defend does not generate file open events on Linux.
Known false positives
- Developer or deployment scripts running on cloud-hosted macOS or Windows instances may read a package registry or source control token and then request instance role credentials from the same interpreter (for example a release script that publishes a package and uploads artifacts with the instance role). Validate the script path, parent process and whether the host is an approved build or release system.
- AI coding assistants running on cloud instances may read their own credential file and then fall back to the instance metadata service for cloud provider authentication (for example Gemini CLI on Google Compute Engine). Confirm the process is the assistant itself and that the credential file belongs to that assistant.
Analyst notes
Investigating Package Runtime Secret File Access Followed by IMDS Request
This rule correlates two behaviors from the same package ecosystem runtime process (process.entity_id) within one
minute: opening a local secret store that cloud SDKs never read, followed by a connection to a cloud instance metadata endpoint
(169.254.169.254, the ECS and EKS Pod Identity credential endpoints, the AWS IPv6 IMDS endpoints, or the Alibaba
Cloud metadata endpoint). Legitimate software rarely needs both an SSH key, registry token or AI assistant credential
and cloud role credentials. Infostealers delivered through compromised packages routinely do both, typically from a
Python or Node.js interpreter that imported the malicious package.
Possible investigation steps
- Identify the process (
process.executable,process.entity_id) and walk its ancestry to determine what launched it. Pay close attention to package managers, CI runners, notebooks, IDEs, AI coding agents, and interpreters executing from virtual environments orsite-packages/node_modules. - Review all file events for the same
process.entity_idto scope which secrets were accessed. Stealers usually enumerate many credential locations in a short burst. - Review all network events for the same
process.entity_idfor outbound connections to non-metadata destinations immediately after the IMDS request, which may indicate exfiltration of the harvested data. - Look for Python
.pthfiles,sitecustomize.py/usercustomize.py, or recently installed or upgraded packages in the interpreter's environment that could have executed the code at import time. - Check cloud audit logs (CloudTrail, GCP Audit, Azure Activity) for use of the instance role credentials from IP addresses outside the instance's expected egress.
False positive analysis
- Release or deployment scripts on cloud-hosted build agents may read a registry or source control token and then request instance role credentials from the same interpreter. Confirm the script is an approved part of a build or release pipeline on that host.
- AI coding assistants on cloud instances may read their own credential file before falling back to the metadata server for cloud authentication. Confirm the process is the assistant that owns the credential file.
Response and remediation
- Isolate the host and terminate the offending process tree.
- Rotate every secret the process opened (SSH keys, npm/PyPI tokens, Git and GitHub CLI tokens, Vault and Terraform tokens, AI assistant OAuth tokens) and revoke active sessions for the instance role or workload identity.
- Identify and remove the malicious package version from the environment, lock files and internal mirrors, and hunt for the same package version across other hosts and CI runners.
- Enforce IMDSv2 with a hop limit of 1 where possible and scope instance roles to least privilege.