-
Notifications
You must be signed in to change notification settings - Fork 645
[New] Elastic Defend Alert from Package Manager Install Ancestry #5905
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
73b250d
[New] Elastic Defend Alert from Package Manager Install Ancestry
Samirbous bba7c00
Merge branch 'main' into packages
Samirbous 020fb7e
Update initial_access_elastic_defend_alert_package_manager_ancestor.toml
Samirbous 0d50b97
Update rules/cross-platform/initial_access_elastic_defend_alert_packa…
Samirbous a8fd0b5
Update rules/cross-platform/initial_access_elastic_defend_alert_packa…
Samirbous fdbbc36
Update initial_access_elastic_defend_alert_package_manager_ancestor.toml
Samirbous File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
136 changes: 136 additions & 0 deletions
136
rules/cross-platform/initial_access_elastic_defend_alert_package_manager_ancestor.toml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,136 @@ | ||
| [metadata] | ||
| creation_date = "2026/03/31" | ||
| maturity = "production" | ||
| min_stack_comments = "ES|QL inline stats became generally available in 9.3.0 and MV_INTERSECTION is in preview since 9.3." | ||
| min_stack_version = "9.3.0" | ||
| updated_date = "2026/03/31" | ||
|
|
||
| [rule] | ||
| author = ["Elastic"] | ||
| description = """ | ||
| 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. | ||
| """ | ||
| from = "now-9m" | ||
| language = "esql" | ||
| license = "Elastic License v2" | ||
| name = "Elastic Defend Alert from Package Manager Install Ancestry" | ||
| note = """## 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 = [ | ||
| "https://attack.mitre.org/techniques/T1195/", | ||
| "https://attack.mitre.org/techniques/T1195/002/", | ||
| ] | ||
| risk_score = 99 | ||
| rule_id = "344e6c7d-ceb0-4f20-ba04-7c75569a7e38" | ||
| severity = "critical" | ||
| tags = [ | ||
| "Domain: Endpoint", | ||
| "Use Case: Threat Detection", | ||
| "Tactic: Initial Access", | ||
| "Rule Type: Higher-Order Rule", | ||
| "Resources: Investigation Guide", | ||
| "Data Source: Elastic Defend", | ||
| ] | ||
| timestamp_override = "event.ingested" | ||
| type = "esql" | ||
|
|
||
| query = ''' | ||
| FROM logs-endpoint.alerts-*, logs-endpoint.events.process-* METADATA _id, _version, _index | ||
|
|
||
| | EVAL is_pkg_install = CASE( | ||
| // npm npx yarn pnpm (Node.js ecosystem) | ||
| process.parent.name IN ("node", "node.exe") AND ( | ||
| process.parent.command_line LIKE "*npm install*" OR | ||
| process.parent.command_line LIKE "*npm i *" OR | ||
| ends_with(process.parent.command_line, "npm i") OR | ||
| process.parent.command_line LIKE "*npx *" OR | ||
| process.parent.command_line LIKE "*yarn install*" OR | ||
| process.parent.command_line LIKE "*yarn add*" OR | ||
| process.parent.command_line LIKE "*pnpm install*" OR | ||
| process.parent.command_line LIKE "*pnpm add*" OR | ||
| process.parent.command_line LIKE "*npm-cli.js*install*" OR | ||
| process.parent.command_line LIKE "*setup.js*" | ||
| ), true, | ||
|
|
||
| // pip pip3 pipx poetry uv (Python ecosystem) | ||
| ((process.parent.name like "python*" or process.parent.name like "pip*" or process.parent.name IN ("uv", "uv.exe") ) AND ( | ||
| process.parent.command_line LIKE "*pip install*" OR | ||
| process.parent.command_line LIKE "*pip3 install*" OR | ||
| process.parent.command_line LIKE "*-m pip install*" OR | ||
| process.parent.command_line LIKE "*setup.py install*" OR | ||
| process.parent.command_line LIKE "*setup.py develop*" OR | ||
| process.parent.command_line LIKE "*pipx install*" OR | ||
| process.parent.command_line LIKE "*poetry install*" OR | ||
| process.parent.command_line LIKE "*poetry add*" OR | ||
| process.parent.command_line LIKE "*uv pip install*" OR | ||
| process.parent.command_line LIKE "*uv add*")), true, | ||
|
|
||
| // cargo (Rust / crates.io ecosystem) | ||
| process.parent.name IN ("cargo", "cargo.exe", "rustc", "rustc.exe") AND ( | ||
| process.parent.command_line LIKE "*cargo install*" OR | ||
| process.parent.command_line LIKE "*cargo build*" OR | ||
| process.parent.command_line LIKE "*cargo run*" OR | ||
| process.parent.command_line LIKE "*cargo fetch*"), true, | ||
|
|
||
| false | ||
| ) | ||
|
|
||
| | WHERE process.Ext.ancestry IS NOT NULL AND (event.dataset == "endpoint.alerts" OR is_pkg_install) | ||
|
|
||
| // Capture entity_ids for package install parent processes | ||
| | EVAL all_entity_id = CASE(is_pkg_install, process.parent.entity_id, "null") | ||
|
|
||
| // Collect all package install entity_ids globally | ||
| | INLINE STATS all_pkg_entity_ids = VALUES(all_entity_id) WHERE all_entity_id != "null" | ||
|
Samirbous marked this conversation as resolved.
|
||
|
|
||
| // Find which package install entity_ids appear in this process's ancestry | ||
| | EVAL Esql.pkg_ancestor_ids = MV_INTERSECTION(all_pkg_entity_ids, process.Ext.ancestry) | ||
|
|
||
| // Elastic Defend alerts descended from a package install process | ||
| | WHERE Esql.pkg_ancestor_ids IS NOT NULL AND event.dataset == "endpoint.alerts" | ||
|
|
||
| | KEEP * | ||
| ''' | ||
|
|
||
| [[rule.threat]] | ||
| framework = "MITRE ATT&CK" | ||
| [[rule.threat.technique]] | ||
| id = "T1195" | ||
| name = "Supply Chain Compromise" | ||
| reference = "https://attack.mitre.org/techniques/T1195/" | ||
| [[rule.threat.technique.subtechnique]] | ||
| id = "T1195.002" | ||
| name = "Compromise Software Supply Chain" | ||
| reference = "https://attack.mitre.org/techniques/T1195/002/" | ||
|
|
||
| [rule.threat.tactic] | ||
| id = "TA0001" | ||
| name = "Initial Access" | ||
| reference = "https://attack.mitre.org/tactics/TA0001/" | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.