Elastic Defend Alert from Package Manager Install Ancestry

Detects Elastic Defend alerts (behavior, malicious file, memory signature, shellcode) where the alerted process has a package-manager install context in its ancestry: npm (Node.js), PyPI (pip / Python / uv), or Rust (cargo). Install-time spawn chains are a common path for supply-chain and postinstall abuse; this Higher-Order rule surfaces Defend alerts whose process tree includes such activity for prioritization.

Elastic rule (View on GitHub)

  1[metadata]
  2creation_date = "2026/03/31"
  3maturity = "production"
  4min_stack_comments = "ES|QL inline stats became generally available in 9.3.0 and MV_INTERSECTION is in preview since 9.3."
  5min_stack_version = "9.3.0"
  6updated_date = "2026/09/18"
  7
  8[rule]
  9author = ["Elastic"]
 10description = """
 11Detects Elastic Defend alerts (behavior, malicious file, memory signature, shellcode) where the alerted process has a
 12package-manager install context in its ancestry: npm (Node.js), PyPI (pip / Python / uv), or Rust (cargo). Install-time
 13spawn chains are a common path for supply-chain and postinstall abuse; this Higher-Order rule surfaces Defend alerts
 14whose process tree includes such activity for prioritization.
 15"""
 16from = "now-9m"
 17language = "esql"
 18license = "Elastic License v2"
 19name = "Elastic Defend Alert from Package Manager Install Ancestry"
 20note = """## Triage and analysis
 21
 22### Investigating Elastic Defend Alert from Package Manager Install Ancestry
 23
 24Elastic Defend raised an alert on a process whose ancestry includes a parent that was involved in a package install
 25(npm, pip/PyPI, or cargo/crates.io). That can indicate malicious postinstall scripts, dependency confusion, or
 26compromised packages.
 27
 28### Possible investigation steps
 29
 30- Identify the install context by finding a process whose `entity_id` appears in `Esql.pkg_ancestor_ids` (intersection
 31  with `process.Ext.ancestry`).
 32- Review `process.command_line` and `process.parent.command_line` for the install command and any script hooks
 33  (e.g. `preinstall`, `postinstall`, `setup.py`, build scripts).
 34- Correlate package name, registry, and lockfile or manifest on the host if available.
 35- Pivot on host, user, and network for additional alerts or outbound connections from the same tree.
 36
 37### False positive analysis
 38
 39- Normal `npm install`, `pip install`, and `cargo build` / `cargo install` during development or CI can produce alerts
 40  on descendant processes. Tune by excluding known-safe Defend rule names, paths, or command-line patterns.
 41
 42### Response and remediation
 43
 44- If abuse is confirmed: remove the suspect package, rotate secrets exposed to that environment, and block related IOCs.
 45"""
 46references = [
 47    "https://attack.mitre.org/techniques/T1195/",
 48    "https://attack.mitre.org/techniques/T1195/002/",
 49]
 50risk_score = 99
 51rule_id = "344e6c7d-ceb0-4f20-ba04-7c75569a7e38"
 52severity = "critical"
 53tags = [
 54    "Domain: Endpoint",
 55    "Use Case: Threat Detection",
 56    "Tactic: Initial Access",
 57    "Rule Type: Higher-Order Rule",
 58    "Resources: Investigation Guide",
 59    "Data Source: Elastic Defend",
 60    "Noise: Low",
 61    "Performance: Normal",
 62    "Profile: Recommended",
 63    "Threat: Supply Chain",
 64    "Rule Type: ES|QL",
 65]
 66timestamp_override = "event.ingested"
 67type = "esql"
 68
 69query = '''
 70FROM logs-endpoint.alerts-*, logs-endpoint.events.process-* METADATA _id, _version, _index
 71
 72| EVAL is_pkg_install = CASE(
 73    // npm  npx  yarn  pnpm (Node.js ecosystem)
 74    process.parent.name IN ("node", "node.exe") AND (
 75      process.parent.command_line LIKE "*npm install*" OR
 76      process.parent.command_line LIKE "*npm i *" OR
 77      ends_with(process.parent.command_line, "npm i") OR
 78      process.parent.command_line LIKE "*npx *" OR
 79      process.parent.command_line LIKE "*yarn install*" OR
 80      process.parent.command_line LIKE "*yarn add*" OR
 81      process.parent.command_line LIKE "*pnpm install*" OR
 82      process.parent.command_line LIKE "*pnpm add*" OR
 83      process.parent.command_line LIKE "*npm-cli.js*install*" OR
 84      process.parent.command_line LIKE "*setup.js*"
 85    ), true,
 86
 87    // pip  pip3 pipx poetry  uv (Python ecosystem)
 88    ((process.parent.name like "python*" or process.parent.name like "pip*" or process.parent.name IN ("uv", "uv.exe") ) AND (
 89      process.parent.command_line LIKE "*pip install*" OR
 90      process.parent.command_line LIKE "*pip3 install*" OR
 91      process.parent.command_line LIKE "*-m pip install*" OR
 92      process.parent.command_line LIKE "*setup.py install*" OR
 93      process.parent.command_line LIKE "*setup.py develop*" OR
 94      process.parent.command_line LIKE "*pipx install*" OR
 95      process.parent.command_line LIKE "*poetry install*" OR
 96      process.parent.command_line LIKE "*poetry add*" OR
 97      process.parent.command_line LIKE "*uv pip install*" OR
 98      process.parent.command_line LIKE "*uv add*")), true,
 99
100    // cargo (Rust / crates.io ecosystem)
101    process.parent.name IN ("cargo", "cargo.exe", "rustc", "rustc.exe") AND (
102      process.parent.command_line LIKE "*cargo install*" OR
103      process.parent.command_line LIKE "*cargo build*" OR
104      process.parent.command_line LIKE "*cargo run*" OR
105      process.parent.command_line LIKE "*cargo fetch*"), true,
106
107    false
108  )
109
110| WHERE process.Ext.ancestry IS NOT NULL AND (data_stream.dataset == "endpoint.alerts" OR is_pkg_install)
111
112// Capture entity_ids for package install parent processes
113| EVAL all_entity_id = CASE(is_pkg_install, process.parent.entity_id, "null")
114
115// Collect all package install entity_ids globally
116| INLINE STATS all_pkg_entity_ids = VALUES(all_entity_id) WHERE all_entity_id != "null"
117
118// Find which package install entity_ids appear in this process's ancestry
119| EVAL Esql.pkg_ancestor_ids = MV_INTERSECTION(all_pkg_entity_ids, process.Ext.ancestry)
120
121// Elastic Defend alerts descended from a package install process
122| WHERE Esql.pkg_ancestor_ids IS NOT NULL AND data_stream.dataset == "endpoint.alerts"
123
124| KEEP *
125'''
126
127[[rule.threat]]
128framework = "MITRE ATT&CK"
129[[rule.threat.technique]]
130id = "T1195"
131name = "Supply Chain Compromise"
132reference = "https://attack.mitre.org/techniques/T1195/"
133[[rule.threat.technique.subtechnique]]
134id = "T1195.002"
135name = "Compromise Software Supply Chain"
136reference = "https://attack.mitre.org/techniques/T1195/002/"
137
138[rule.threat.tactic]
139id = "TA0001"
140name = "Initial Access"
141reference = "https://attack.mitre.org/tactics/TA0001/"

Triage and analysis

Investigating Elastic Defend Alert from Package Manager Install Ancestry

Elastic Defend raised an alert on a process whose ancestry includes a parent that was involved in a package install (npm, pip/PyPI, or cargo/crates.io). That can indicate malicious postinstall scripts, dependency confusion, or compromised packages.

Possible investigation steps

  • Identify the install context by finding a process whose entity_id appears in Esql.pkg_ancestor_ids (intersection with process.Ext.ancestry).
  • Review process.command_line and process.parent.command_line for the install command and any script hooks (e.g. preinstall, postinstall, setup.py, build scripts).
  • Correlate package name, registry, and lockfile or manifest on the host if available.
  • Pivot on host, user, and network for additional alerts or outbound connections from the same tree.

False positive analysis

  • Normal npm install, pip install, and cargo build / cargo install during development or CI can produce alerts on descendant processes. Tune by excluding known-safe Defend rule names, paths, or command-line patterns.

Response and remediation

  • If abuse is confirmed: remove the suspect package, rotate secrets exposed to that environment, and block related IOCs.

References

Related rules

to-top