elastic / elastic/detection-rules
[New Rule] Shai-Hulud Exfiltration Artifact File Creation
- Dominant language
- Python
- Stars
- 2.7k
- Forks
- 696
- Avg merge
- 4d 17h
- Merged PRs (30d)
- 87
Description
## Description
Detects a Node.js or Bun process creating one of the staging artifact files used by the Shai-Hulud npm worm family to collect harvested secrets before exfiltration (`cloud.json`, `contents.json`, `environment.json`, `truffleSecrets.json`, `actionsSecrets.json`). Elastic's existing `execution_nodejs_pre_or_post_install_script_execution` rule detects the *execution* side of this worm's install-time chain, but nothing in the ruleset detects the *artifact* side: the staged files it writes before exfiltrating them. Real GitHub Security Labs reporting on this worm family confirms it specifically installs and uses the Bun runtime (via `setup_bun.js`/`bun_environment.js`) partly to evade standard Node.js-focused monitoring, so both runtimes are in scope.
**Behavior-based** (an artifact-naming + process-origin pattern), not a specific hash/IOC.
**Real, serious false-positive risk found and fixed before proposing** (documented transparently): an earlier draft matched these filenames anywhere on the filesystem, by any process. A real GitHub code search found `contents.json` alone appears in **6.4 million** public files (predominantly Xcode `.xcassets` asset-catalog metadata, a near-universal filename on macOS/iOS projects, unrelated to this worm) and `environment.json` in **58,240** (common Postman/Angular config). The Splunk `security_content` detection this was ported from explicitly warns about exactly this risk in its own documentation but doesn't itself mitigate it. Fixed by requiring the creating process to be `node` or `bun`.
**Re-validated after the fix**: a real `node -e` process performing the exact file-write technique (`fs.writeFileSync` to `environment.json`) confirmed as the true positive. Xcode's asset compiler and Postman's own process are not named `node`/`bun` and are excluded by construction (a deterministic process-name check, not an unvalidated assumption).
## Target Ruleset
cross-platform
## Target Rule Type
Event Correlation (EQL)
## Tested ECS Version
Validated against the `logs-endpoint.events.file*` schema. Real capture was performed via kernel-level file-write auditing (this host's kernel doesn't support Elastic Defend's eBPF sensor) and reshaped into the equivalent ECS file-event schema for validation, noted transparently.
## Query
```eql
file where host.os.type in ("linux", "macos", "windows") and event.type in ("creation", "change") and
file.name in ("cloud.json", "contents.json", "environment.json", "truffleSecrets.json", "actionsSecrets.json") and
process.name in ("node", "bun")
```
## New fields required in ECS/data sources for this rule?
None. Standard `file.name`/`process.name` ECS fields.
## Related issues or PRs
None yet. Part of a small batch from a personal detection-gap research project (real-telemetry validated throughout).
## References
- https://www.wiz.io/blog/shai-hulud-2-0-ongoing-supply-chain-attack
- https://www.elastic.co/blog/shai-hulud-worm-2-0-updated-response
- https://securitylabs.datadoghq.com/articles/shai-hulud-2.0-npm-worm/
- https://github.com/splunk/security_content (original ported detection, "Shai-Hulud 2 Exfiltration Artifact Files")
## Redacted Example Data
Real true positive (a real `node -e` process performing the exact artifact-write technique):
```json
{
"event": { "category": ["file"], "type": ["creation"], "action": "creation" },
"process": { "name": "node", "args": ["node", "-e", "require('fs').writeFileSync('environment.json', JSON.stringify({...}))"] },
"file": { "name": "environment.json", "path": "/tmp/build/environment.json" }
}
```
Real, confirmed false-positive class avoided by this rule's process scoping (illustrative, based on real GitHub-search-confirmed prevalence rather than a live Xcode capture, since no macOS host was available for this pass): an Xcode asset-catalog compiler writing `Contents.json` as part of ordinary `.xcassets` builds would not match, since its process name is not `node`/`bun`.
Contributor guide
Research direction
Start by locating the existing execution_nodejs_pre_or_post_install_script_execution rule and reviewing the cross-platform Event Correlation (EQL) conventions around it. Add the artifact-file creation detection with the stated process and ECS field constraints, then validate it against the logs-endpoint.events.file* schema using the redacted node true-positive example and the described false-positive cases.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- bun, node.js
- Domain
- security
- Issue type
- Feature
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 58/100