elastic / elastic/detection-rules

[New Rule] Shai-Hulud Exfiltration Artifact File Creation

Open
#6,602 2 comments 0 reactions 0 assignees View on GitHub
community
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.