Package Runtime Secret File Access Followed by IMDS Request
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.
Elastic rule (View on GitHub)
1[metadata]
2creation_date = "2026/10/23"
3integration = ["endpoint"]
4maturity = "production"
5updated_date = "2026/10/23"
6
7[rule]
8author = ["Elastic"]
9description = """
10Identifies a Python, Node.js, Bun, Deno, Ruby, PHP or Perl runtime, or a binary executing from a package install
11location, that opens a developer secret (SSH keys, package registry tokens, source control credentials or AI coding
12assistant credentials) and then connects to a cloud instance metadata service (IMDS) endpoint within one minute. This
13sequence matches credential stealers delivered through compromised packages, such as the malicious LiteLLM PyPI
14releases, while cloud provider credential files are excluded because legitimate cloud SDK credential chains read them
15before falling back to IMDS.
16"""
17false_positives = [
18 """
19 Developer or deployment scripts running on cloud-hosted macOS or Windows instances may read a package registry or
20 source control token and then request instance role credentials from the same interpreter (for example a release
21 script that publishes a package and uploads artifacts with the instance role). Validate the script path, parent
22 process and whether the host is an approved build or release system.
23 """,
24 """
25 AI coding assistants running on cloud instances may read their own credential file and then fall back to the
26 instance metadata service for cloud provider authentication (for example Gemini CLI on Google Compute Engine).
27 Confirm the process is the assistant itself and that the credential file belongs to that assistant.
28 """,
29]
30from = "now-9m"
31index = ["logs-endpoint.events.file-*", "logs-endpoint.events.network-*"]
32language = "eql"
33license = "Elastic License v2"
34name = "Package Runtime Secret File Access Followed by IMDS Request"
35note = """## Triage and analysis
36
37### Investigating Package Runtime Secret File Access Followed by IMDS Request
38
39This rule correlates two behaviors from the same package ecosystem runtime process (`process.entity_id`) within one
40minute: opening a local secret store that cloud SDKs never read, followed by a connection to a cloud instance metadata endpoint
41(`169.254.169.254`, the ECS and EKS Pod Identity credential endpoints, the AWS IPv6 IMDS endpoints, or the Alibaba
42Cloud metadata endpoint). Legitimate software rarely needs both an SSH key, registry token or AI assistant credential
43and cloud role credentials. Infostealers delivered through compromised packages routinely do both, typically from a
44Python or Node.js interpreter that imported the malicious package.
45
46### Possible investigation steps
47
48- Identify the process (`process.executable`, `process.entity_id`) and walk its ancestry to determine what launched it.
49 Pay close attention to package managers, CI runners, notebooks, IDEs, AI coding agents, and interpreters executing
50 from virtual environments or `site-packages`/`node_modules`.
51- Review all file events for the same `process.entity_id` to scope which secrets were accessed. Stealers usually
52 enumerate many credential locations in a short burst.
53- Review all network events for the same `process.entity_id` for outbound connections to non-metadata destinations
54 immediately after the IMDS request, which may indicate exfiltration of the harvested data.
55- Look for Python `.pth` files, `sitecustomize.py`/`usercustomize.py`, or recently installed or upgraded packages in the
56 interpreter's environment that could have executed the code at import time.
57- Check cloud audit logs (CloudTrail, GCP Audit, Azure Activity) for use of the instance role credentials from IP
58 addresses outside the instance's expected egress.
59
60### False positive analysis
61
62- Release or deployment scripts on cloud-hosted build agents may read a registry or source control token and then
63 request instance role credentials from the same interpreter. Confirm the script is an approved part of a build or
64 release pipeline on that host.
65- AI coding assistants on cloud instances may read their own credential file before falling back to the metadata server
66 for cloud authentication. Confirm the process is the assistant that owns the credential file.
67
68### Response and remediation
69
70- Isolate the host and terminate the offending process tree.
71- Rotate every secret the process opened (SSH keys, npm/PyPI tokens, Git and GitHub CLI tokens, Vault and Terraform
72 tokens, AI assistant OAuth tokens) and revoke active sessions for the instance role or workload identity.
73- Identify and remove the malicious package version from the environment, lock files and internal mirrors, and hunt for
74 the same package version across other hosts and CI runners.
75- Enforce IMDSv2 with a hop limit of 1 where possible and scope instance roles to least privilege.
76"""
77risk_score = 73
78rule_id = "2baf0a3c-50cd-43b1-9e9a-d7ff3153b36b"
79setup = """## Setup
80
81This rule requires data from Elastic Defend with file and network event collection enabled.
82
83Elastic Defend only generates file `open` events on macOS and Windows, and only for paths in its event-on-access file
84path list. That list is delivered through the Elastic Defend global configuration artifact and can be extended per
85policy with the `advanced.events.event_on_access.file_paths` advanced setting. Credential paths in this rule that are
86not yet present in the deployed global configuration only match after they are added to that setting. On Windows,
87repeated access events for the same path are deduplicated for one hour by default.
88
89This rule is scoped to macOS and Windows because Elastic Defend does not generate file `open` events on Linux.
90"""
91severity = "high"
92tags = [
93 "Domain: Endpoint",
94 "Domain: Cloud",
95 "OS: macOS",
96 "OS: Windows",
97 "Use Case: Threat Detection",
98 "Tactic: Credential Access",
99 "Tactic: Initial Access",
100 "Data Source: Elastic Defend",
101 "Resources: Investigation Guide",
102 "Threat: Supply Chain",
103 "Threat: IMDS Credential Theft",
104 "Rule Type: Event Correlation (EQL)",
105 "Platform: macOS",
106 "Platform: Windows",
107 "Domain: GenAI",
108 "Mitre Atlas: AML.T0010",
109 "Mitre Atlas: AML.T0010.001",
110 "Mitre Atlas: AML.T0055",
111 "Mitre Atlas: AML.T0083",
112]
113type = "eql"
114
115query = '''
116sequence by process.entity_id with maxspan=1m
117 [file where event.action == "open" and host.os.type in ("macos", "windows") and
118 file.path like~ (
119 /* SSH private keys */
120 "/Users/*/.ssh/id_*", "?:\\Users\\*\\.ssh\\id_*",
121
122 /* Package registry, source control and secrets manager tokens */
123 "/Users/*/.npmrc", "?:\\Users\\*\\.npmrc",
124 "/Users/*/.pypirc", "?:\\Users\\*\\.pypirc",
125 "/Users/*/.git-credentials", "?:\\Users\\*\\.git-credentials",
126 "/Users/*/.config/git/credentials", "?:\\Users\\*\\.config\\git\\credentials",
127 "/Users/*/.config/gh/hosts.yml", "?:\\Users\\*\\AppData\\Roaming\\GitHub CLI\\hosts.yml",
128 "/Users/*/.vault-token", "?:\\Users\\*\\.vault-token",
129 "/Users/*/.terraform.d/credentials.tfrc.json", "?:\\Users\\*\\AppData\\Roaming\\terraform.d\\credentials.tfrc.json",
130
131 /* Additional package registry and AI/ML platform tokens */
132 "/Users/*/.yarnrc.yml", "?:\\Users\\*\\.yarnrc.yml",
133 "/Users/*/.gem/credentials", "?:\\Users\\*\\.gem\\credentials",
134 "/Users/*/.cargo/credentials.toml", "?:\\Users\\*\\.cargo\\credentials.toml",
135 "/Users/*/.composer/auth.json", "/Users/*/.config/composer/auth.json", "?:\\Users\\*\\AppData\\Roaming\\Composer\\auth.json",
136 "/Users/*/.cache/huggingface/token", "/Users/*/.huggingface/token", "?:\\Users\\*\\.cache\\huggingface\\token", "?:\\Users\\*\\.huggingface\\token",
137 "/Users/*/.config/github-copilot/apps.json", "/Users/*/.config/github-copilot/hosts.json",
138 "?:\\Users\\*\\AppData\\Local\\github-copilot\\apps.json", "?:\\Users\\*\\AppData\\Local\\github-copilot\\hosts.json",
139 "/Users/*/.ollama/id_ed25519", "?:\\Users\\*\\.ollama\\id_ed25519",
140
141 /* AI coding assistant credentials */
142 "/Users/*/.claude/.credentials.json", "?:\\Users\\*\\.claude\\.credentials.json",
143 "/Users/*/.codex/auth.json", "?:\\Users\\*\\.codex\\auth.json",
144 "/Users/*/.codex/.credentials.json", "?:\\Users\\*\\.codex\\.credentials.json",
145 "/Users/*/.codex/secrets/*.age", "?:\\Users\\*\\.codex\\secrets\\*.age",
146 "/Users/*/.gemini/oauth_creds.json", "?:\\Users\\*\\.gemini\\oauth_creds.json",
147 "/Users/*/.gemini/gemini-credentials.json", "?:\\Users\\*\\.gemini\\gemini-credentials.json",
148 "/Users/*/.gemini/mcp-oauth-tokens.json", "?:\\Users\\*\\.gemini\\mcp-oauth-tokens.json",
149 "/Users/*/.gemini/a2a-oauth-tokens.json", "?:\\Users\\*\\.gemini\\a2a-oauth-tokens.json",
150 "/Users/*/.qwen/oauth_creds.json", "?:\\Users\\*\\.qwen\\oauth_creds.json",
151 "/Users/*/.qwen/mcp-oauth-tokens.json", "?:\\Users\\*\\.qwen\\mcp-oauth-tokens.json",
152 "/Users/*/.aws/sso/cache/kiro-auth-token.json", "?:\\Users\\*\\.aws\\sso\\cache\\kiro-auth-token.json",
153 "/Users/*/.local/share/opencode/auth.json", "?:\\Users\\*\\.local\\share\\opencode\\auth.json",
154 "/Users/*/.local/share/opencode/mcp-auth.json", "?:\\Users\\*\\.local\\share\\opencode\\mcp-auth.json",
155 "/Users/*/.local/share/amp/secrets.json", "?:\\Users\\*\\.local\\share\\amp\\secrets.json",
156 "/Users/*/.augment/session.json", "?:\\Users\\*\\.augment\\session.json",
157 "/Users/*/.kimi/credentials/kimi-code.json", "?:\\Users\\*\\.kimi\\credentials\\kimi-code.json",
158 "/Users/*/.cursor/auth.json", "?:\\Users\\*\\.cursor\\auth.json",
159 "/Users/*/.pi/agent/auth.json", "?:\\Users\\*\\.pi\\agent\\auth.json",
160 "/Users/*/.config/goose/secrets.yaml", "?:\\Users\\*\\AppData\\Roaming\\Block\\goose\\config\\secrets.yaml",
161 "/Users/*/.config/muse/auth.json", "?:\\Users\\*\\.config\\muse\\auth.json",
162 "/Users/*/.local/share/devin/credentials.toml", "?:\\Users\\*\\AppData\\Roaming\\devin\\credentials.toml",
163 "/Users/*/.openclaw/credentials/oauth.json", "?:\\Users\\*\\.openclaw\\credentials\\oauth.json",
164 "/Users/*/.openclaw/agents/*/agent/auth-profiles.json", "?:\\Users\\*\\.openclaw\\agents\\*\\agent\\auth-profiles.json",
165 "/Users/*/.openclaw/agents/*/agent/auth.json", "?:\\Users\\*\\.openclaw\\agents\\*\\agent\\auth.json"
166 ) and
167
168 /* SSH public keys are not secrets and are routinely read by SSH and cloud tooling */
169 not file.path like~ "*.pub" and
170
171 /* Package ecosystem runtimes or binaries executing from package install locations */
172 (
173 process.name like~ ("python*", "node", "node.exe", "nodejs", "bun", "bun.exe", "deno", "deno.exe", "ruby*", "php*", "perl*") or
174 process.executable like~ ("*/site-packages/*", "*/dist-packages/*", "*/node_modules/*", "*\\site-packages\\*", "*\\node_modules\\*",
175 "*/.venv/*", "*/venv/*", "*\\.venv\\*", "*\\venv\\*")
176 )
177 ]
178 [network where
179 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
180 destination.port == 80 and event.action == "connection_attempted" and host.os.type in ("macos", "windows")
181 ]
182'''
183
184
185[[rule.threat]]
186framework = "MITRE ATT&CK"
187[[rule.threat.technique]]
188id = "T1552"
189name = "Unsecured Credentials"
190reference = "https://attack.mitre.org/techniques/T1552/"
191[[rule.threat.technique.subtechnique]]
192id = "T1552.001"
193name = "Credentials In Files"
194reference = "https://attack.mitre.org/techniques/T1552/001/"
195
196[[rule.threat.technique.subtechnique]]
197id = "T1552.004"
198name = "Private Keys"
199reference = "https://attack.mitre.org/techniques/T1552/004/"
200
201[[rule.threat.technique.subtechnique]]
202id = "T1552.005"
203name = "Cloud Instance Metadata API"
204reference = "https://attack.mitre.org/techniques/T1552/005/"
205
206
207
208[rule.threat.tactic]
209id = "TA0006"
210name = "Credential Access"
211reference = "https://attack.mitre.org/tactics/TA0006/"
212[[rule.threat]]
213framework = "MITRE ATT&CK"
214[[rule.threat.technique]]
215id = "T1195"
216name = "Supply Chain Compromise"
217reference = "https://attack.mitre.org/techniques/T1195/"
218[[rule.threat.technique.subtechnique]]
219id = "T1195.001"
220name = "Compromise Software Dependencies and Development Tools"
221reference = "https://attack.mitre.org/techniques/T1195/001/"
222
223
224
225[rule.threat.tactic]
226id = "TA0001"
227name = "Initial Access"
228reference = "https://attack.mitre.org/tactics/TA0001/"
229[[rule.threat_mappings]]
230framework = "MITRE ATLAS"
231version = "2026.08"
232[[rule.threat_mappings.threat]]
233framework = "MITRE ATLAS"
234[[rule.threat_mappings.threat.technique]]
235id = "AML.T0010"
236name = "AI Supply Chain Compromise"
237reference = "https://atlas.mitre.org/techniques/AML.T0010/"
238[[rule.threat_mappings.threat.technique.subtechnique]]
239id = "AML.T0010.001"
240name = "AI Software"
241reference = "https://atlas.mitre.org/techniques/AML.T0010.001/"
242
243
244
245[rule.threat_mappings.threat.tactic]
246id = "AML.TA0004"
247name = "Initial Access"
248reference = "https://atlas.mitre.org/tactics/AML.TA0004/"
249[[rule.threat_mappings.threat]]
250framework = "MITRE ATLAS"
251[[rule.threat_mappings.threat.technique]]
252id = "AML.T0055"
253name = "Unsecured Credentials"
254reference = "https://atlas.mitre.org/techniques/AML.T0055/"
255
256[[rule.threat_mappings.threat.technique]]
257id = "AML.T0083"
258name = "Credentials from AI Agent Configuration"
259reference = "https://atlas.mitre.org/techniques/AML.T0083/"
260
261
262[rule.threat_mappings.threat.tactic]
263id = "AML.TA0013"
264name = "Credential Access"
265reference = "https://atlas.mitre.org/tactics/AML.TA0013/"
Triage and analysis
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.
Related rules
- GenAI Process Accessing Sensitive Files
- Suspicious Instance Metadata Service (IMDS) API Command Line Execution
- Ollama API Accessed from External Network
- Execution via GitHub Actions Runner
- Multi-Cloud CLI Token and Credential Access Commands