IronWorm — Rust-Built npm Supply-Chain Worm
Executive Summary
IronWorm (identified by JFrog on 3 Jun 2026) is an evolved variant of the Shai-Hulud worm family, distributed through ~37–43 npm packages published from the compromised asteroiddao account and aimed at the Arweave/WeaveDB decentralized-database and broader Web3/crypto developer ecosystem. Unlike the JS-only Shai-Hulud waves, IronWorm's install hook drops a ~976 KB native Rust ELF (tools/setup, UPX-packed with an overwritten magic to defeat unpackers).
The ELF aggressively harvests ~86 environment variables and 20+ credential file paths (cloud keys, AI API keys, SCM/registry/CI tokens, Kubernetes/Vault secrets), captures Exodus desktop-wallet seed phrases, and deploys an eBPF kernel rootkit to hide its processes/sockets and resist debugging. It exfiltrates to a Tor hidden service (path /api/agent) with a temp.sh fallback, and self-propagates by abusing stolen npm publishing credentials — including npm's Trusted Publishing workflow. The actor made 57 backdated malicious commits across nine organizations to muddy the timeline.
node_modules being chmod'd/executed) and Q3 (an eBPF program load by a non-system process). Treat any affected dev host/runner as fully compromised — the eBPF rootkit means you can't trust on-host visibility; rebuild.
Source Review & Web Hunter Notes
| Tier | Source | Key Finding | Carry |
|---|---|---|---|
| 1 · Vendor research | Phoenix Security — IronWorm (Rust/eBPF/Tor) | Rust ELF, eBPF rootkit, Tor C2, self-propagation; 37 packages; full chain | yes |
| 1 · Vendor research | SafeDep / OX Security — IronWorm campaign | asteroiddao account; cred/env harvesting scope; npm Trusted-Publishing abuse | yes |
| 1 · News of record | BleepingComputer / The Hacker News / Dark Reading | 36–37 packages; Shai-Hulud-family lineage; Miasma variant alongside | yes |
| 2 · Vendor | Cyberpress — developer-secret theft | 86 env vars, 20+ cred files, Exodus wallet seeds, temp.sh fallback | yes |
Decisions: dev/CI-CD-first (native SCA + npm-token audit are primary); endpoint CQL covers the install-hook → ELF → eBPF/Tor behaviors on Linux/macOS dev hosts; flagged that the eBPF rootkit undermines on-host trust (rebuild, don't clean); cross-references the Shai-Hulud "Hades" + Mini Shai-Hulud sibling packs (same worm family).
Hunt Brief & Attack Chain
Working hypothesis: A dev/runner installs a trojanized npm package; the install hook drops and runs the Rust ELF, which harvests secrets + wallet seeds, loads an eBPF rootkit, exfiltrates over Tor, and re-publishes via stolen npm tokens.
| Step | Behavior | Telemetry | Hunt Angle |
|---|---|---|---|
| 1 · Install | npm installs a trojanized package; install hook fires | npm exec | N1; Q1 |
| 2 · Drop ELF | ~976 KB Rust ELF written to tools/setup in node_modules; chmod +x; execute | file write; ProcessRollup2 | Q1 / Q2 |
| 3 · Rootkit | eBPF program loaded to hide processes/sockets; anti-debug | bpf syscall (eBPF) | Q3; N3 |
| 4 · Harvest | Read ~86 env vars + 20+ cred files; Exodus wallet seeds | file read | Q4 |
| 5 · Exfil | Beacon to Tor hidden service /api/agent; temp.sh fallback | network; DNS | Q5 |
| 6 · Worm | Re-publish to npm via stolen Trusted-Publishing creds | npm publish audit | Q6; N4 |
Affected surface & telemetry
| Surface | Required Telemetry | Priority | Gap Risk |
|---|---|---|---|
| Developer workstations (Linux/macOS) | Process + file telemetry; eBPF/syscall visibility | Critical | High — eBPF rootkit hides on-host artifacts |
| CI/CD runners | Runner process/network; npm token use | Critical | High — ephemeral & often unmonitored |
| npm registry | SCA + Trusted-Publishing token audit | High | Low — lockfile/SBOM + token review |
| Network egress | Tor / temp.sh connections | Medium | Medium — Tor blends/rotates |
Consolidated IOC Table
| Type | Value | Conf | Action | Context |
|---|---|---|---|---|
| File | tools/setup (~976 KB UPX-packed Rust ELF, overwritten magic) | high | hunt | The dropped implant |
| Account | npm publisher: asteroiddao (43 packages) | high | detect | Compromised publisher — pin away |
| Behavior | eBPF program load by a non-system process (rootkit) | high | detect | Process/socket hiding |
| Network | Tor hidden-service beacon (/api/agent) · temp.sh fallback exfil | medium | hunt | C2 / exfil |
| Behavior | npm re-publish via stolen Trusted-Publishing creds | medium | hunt | Self-propagation |
ATT&CK Mapping
| Tactic | Technique | Observed Behavior | Query / Control |
|---|---|---|---|
| Initial Access | T1195.002 — Compromise Software Supply Chain | Trojanized npm packages (asteroiddao) | N1; SCA (§10) |
| Execution | T1059.007 / T1106 — JS hook / native ELF | install hook drops + runs Rust ELF | Q1, Q2 |
| Defense Evasion | T1014 / T1562.001 — Rootkit (eBPF) | Process/socket hiding; anti-debug | Q3; N3 |
| Credential Access | T1552.001 / .005 / T1539 — Files / env / wallet seeds | 86 env vars, 20+ cred files, Exodus seeds | Q4 |
| C2 / Exfiltration | T1090.003 / T1567 — Tor / web exfil | Tor hidden service + temp.sh | Q5 |
| Lateral / Impact | T1195.002 (worm) — re-publish via stolen tokens | npm Trusted-Publishing abuse | Q6; N4 |
Native Audit-Log Hunts (dev / CI-CD — primary surface)
| Hunt | Source | Logic | Response |
|---|---|---|---|
| N1 · Affected-package inventory | SCA / SBOM / lockfiles | Any project resolving a package from the asteroiddao publisher / IronWorm advisory list | Pin away; rebuild; rotate |
| N2 · Rust-ELF artifact scan | Endpoint file scan (where eBPF hasn't hidden it) | ~976 KB UPX-packed ELF at node_modules/.../tools/setup with overwritten magic | Rebuild host (don't trust clean) |
| N3 · eBPF / kernel object audit | bpftool prog list / kernel audit / Falcon kernel telemetry | Unexpected eBPF programs/maps loaded by a non-system process | Treat host as rootkitted; rebuild |
| N4 · npm token / publish audit | npm publish + Trusted-Publishing logs | Unexpected publishes / OIDC-trusted-publish from your org's tokens | Revoke tokens; unpublish; report |
| N5 · Tor / temp.sh egress | Proxy / firewall / DNS | Dev-host connections to Tor entry nodes or temp.sh | Block; isolate the source |
CrowdStrike LogScale CQL Hunt Queries
Looks for: npm/node spawning chmod/exec of a binary under node_modules (esp. tools/setup). Accomplishes: catches the ELF drop+run. FP: some native modules ship binaries — verify path/size.
// HUNT: IronWorm install hook drops/executes a native ELF (tools/setup) // MITRE: T1195.002, T1106 | CONF: high FP: low-med COST: low // FP NOTES: some native modules ship binaries; flag tools/setup + chmod + exec from node_modules #event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/ | ParentBaseFileName=/^(npm|node|yarn|pnpm)$/i | (CommandLine=/node_modules\/.+\/tools\/setup/i or (FileName=/^chmod$/i and CommandLine=/node_modules\/.+(setup|bin)/i)) | table([@timestamp, ComputerName, UserName, ParentBaseFileName, FileName, CommandLine], limit=200)
Looks for: an ELF/Mach-O written to a tools/ path inside node_modules during install. Accomplishes: catches the implant drop pre-execution.
// HUNT: IronWorm native implant written into node_modules // MITRE: T1105 | CONF: high FP: low-med COST: low // TUNING: correlate to Q1; ~976KB UPX-packed; tools/setup path #event_simpleName=/ELFFileWritten|NewExecutableWritten/ | TargetFileName=/node_modules\/.+\/tools\/(setup|bin)/i | table([@timestamp, ComputerName, UserName, ContextBaseFileName, TargetFileName, SHA256HashData], limit=200)
Looks for: a non-system process loading an eBPF program (BPF_PROG_LOAD) or invoking bpf(). Accomplishes: the rootkit load. FP: observability/security agents use eBPF — allow-list them. Requires Linux sensor eBPF/syscall telemetry.
// HUNT: IronWorm eBPF rootkit load (non-system process) // MITRE: T1014, T1562.001 | CONF: high FP: low-med COST: med // REQUIRES: Linux sensor eBPF/syscall telemetry // TUNING: allow-list observability/security agents #event_simpleName=/BpfProgramLoad|SyscallBpf|KernelModuleLoad/ | ImageFileName!=/\/(usr\/(s)?bin|opt\/(falcon|datadog|sysdig|cilium))\//i | table([@timestamp, ComputerName, UserName, ImageFileName, CommandLine], limit=200)
Looks for: a single process opening many credential files (.aws, .npmrc, kube config, Vault, Exodus wallet). Accomplishes: the harvest stage. FP: dev tooling reads some — flag breadth + a node_modules-spawned parent. Requires file-access telemetry.
// HUNT: IronWorm credential/secret harvesting (broad cred-file reads) // MITRE: T1552.001, T1552.005, T1539 | CONF: medium FP: medium COST: med // REQUIRES: file-access telemetry // TUNING: flag breadth + a node_modules-derived parent #event_simpleName=/FileOpen|ProcessFileOpen|OsfmFileOpen/ | TargetFileName=/(\.aws\/credentials|\.npmrc|\.config\/gcloud|kube\/config|\.vault-token|\.docker\/config|Exodus\/exodus\.wallet|\.ssh\/id_)/i | groupBy([aid, ImageFileName], function=[count(field=TargetFileName, distinct=true, as=files)]) | files>=4 | sort(files, order=desc)
Looks for: DNS/connections to temp.sh or Tor entry-node patterns from a dev host. Accomplishes: the exfil channel. FP: low for temp.sh on a dev host; Tor requires an entry-node feed.
// HUNT: IronWorm exfil (temp.sh fallback / Tor) // MITRE: T1567, T1090.003 | CONF: medium FP: low-med COST: low // TUNING: enrich with Tor entry-node feed; temp.sh from a dev host is suspicious #event_simpleName=DnsRequest | DomainName=/(^|\.)(temp\.sh)$/i | table([@timestamp, ComputerName, ContextBaseFileName, DomainName], limit=200)
Looks for: the dropped implant / node contacting registry.npmjs.org outside a sanctioned publish pipeline. Accomplishes: worm re-publish. FP: legit dev tooling — correlate with Q1–Q3 + non-CI host.
// HUNT: IronWorm self-propagation (publish to npm outside a pipeline) // MITRE: T1195.002 | CONF: medium FP: medium COST: med // TUNING: exclude sanctioned publish runners; correlate to Q1-Q3 #event_simpleName=DnsRequest | DomainName=/(^|\.)registry\.npmjs\.org$/i | ContextBaseFileName=/^(node|setup|npm)$/i | table([@timestamp, ComputerName, ContextBaseFileName, DomainName], limit=200)
Detection Recommendations (SCA / npm / kernel)
| Detection | Logic | Benign Exclusions | Deployment Path |
|---|---|---|---|
| Affected-publisher gate | Block/alert on packages from asteroiddao / the IronWorm advisory list | None — hard-block | SCA / dependency firewall / CI gate |
| Unexpected eBPF load | Q3: eBPF program loaded by a non-allow-listed process | Observability/security agents | Falcon kernel IOA / eBPF monitoring |
| Anomalous npm publish | N4: publishes / trusted-publish events outside expected workflows | Sanctioned pipelines | npm audit / SIEM correlation |
Machine-Readable IOC Appendix
Grouped IOC Quick-Copy
One-click blocks for SCA gating, endpoint/kernel sweeps, and response. The eBPF rootkit hides on-host artifacts — favour off-host signals and rebuild affected hosts.
# Compromised npm publisher: asteroiddao (~37-43 packages) # Targets Arweave / WeaveDB / Web3 / crypto-developer packages # Pin away from ALL asteroiddao-published packages; re-verify the exact list vs JFrog/SafeDep advisory # Sibling worm packs (same family): Shai-Hulud "Hades" (PyPI), Mini Shai-Hulud (npm/PyPI) # Hunt package-lock.json / yarn.lock for asteroiddao-published deps
# Implant node_modules/.../tools/setup # ~976 KB Rust ELF, UPX-packed with overwritten magic # Rootkit unexpected eBPF programs/maps (bpftool prog list / bpftool map list) # Exfil Tor hidden-service beacon, path /api/agent ; temp.sh fallback upload # Harvest targets (read by the ELF) ~86 env vars + 20+ cred files: ~/.aws, ~/.npmrc, ~/.config/gcloud, ~/.kube/config, ~/.vault-token, ~/.docker/config.json, ~/.ssh/id_*, Exodus wallet seed
npm/node install hook -> chmod +x + exec of node_modules/.../tools/setup ~976 KB ELF/Mach-O written into a node_modules tools/ path eBPF program/map loaded by a non-system process (process/socket hiding) One process reading many cred/env files (>=4 of: .aws/.npmrc/kube/vault/ssh/Exodus) Dev host connecting to temp.sh or a Tor entry node node/setup contacting registry.npmjs.org outside a sanctioned publish pipeline
# eBPF rootkit = do NOT trust on-host cleanup: 1. Network-isolate affected dev hosts/runners 2. REBUILD from clean images (the rootkit can hide processes/sockets/files) 3. Rotate EVERYTHING reachable: cloud keys, AI API keys, SCM/registry/CI tokens, Kubernetes/Vault secrets, SSH keys, npm publish/Trusted-Publishing tokens 4. Move any Exodus wallet funds to a NEW seed (seed phrase assumed stolen) 5. Audit npm publishes; unpublish worm-pushed versions; SCA hard-block asteroiddao 6. Block Tor + temp.sh egress on dev/build networks
Hardening — Tiered & Deployable
Stop install-time native code and starve the worm of tokens and egress.
- SCA / dependency-firewall: hard-block
asteroiddaopackages — M1016. - Disable npm lifecycle scripts — M1042:
npm ci --ignore-scripts; vet native binaries before allowing. - Egress allow-list on dev/build hosts; block Tor + temp.sh — M1037. Starves exfil (Q5).
- Protect npm Trusted-Publishing: scoped, short-lived OIDC publish; no standing tokens — M1015 / M1026. Breaks self-propagation.
- Restrict unprivileged eBPF (
kernel.unprivileged_bpf_disabled=1) — M1038. Raises the bar for the rootkit. - Keep secrets out of env/files on dev hosts; use a broker / short-lived creds — M1015. Shrinks the harvest.
- Hash-pinned lockfiles + dependency review gate — M1016.
- Ephemeral, network-restricted, secretless build runners — M1015 / M1030.
- Independently verify package provenance; internal mirror with review — M1016.
- Crypto-dev hardware wallets / cold storage; never store seeds on dev hosts — M1027.
Containment Runbook
| Phase | Actions | Owner | Evidence |
|---|---|---|---|
| Isolate | Network-contain affected dev hosts/runners; freeze affected pipelines; capture network evidence off-host (eBPF hides on-host) | SOC / Platform | Containment timestamp; net evidence |
| Triage | Confirm via SCA (asteroiddao deps) + off-host egress (Tor/temp.sh); enumerate reachable secrets/tokens | IR | SCA results; secret reachability |
| Eradicate | Rebuild hosts/runners from clean images (do not clean — rootkit); revoke npm tokens; unpublish worm versions | IR / Platform | Rebuild tickets; revoked tokens |
| Recover | Rotate ALL reachable creds; move Exodus funds to a new seed; restore clean pinned deps | IR / IT | Rotation log; new wallet |
| Harden | SCA gate; disable lifecycle scripts; restrict eBPF; egress allow-list; scope OIDC publish; promote Q1/Q3 | Platform / Detection Eng | Control status; detections enabled |
Detection Coverage Map & Validation
| Technique | Behavior | CQL | Native | Coverage |
|---|---|---|---|---|
| T1195.002 | Trojanized package install + ELF drop | Q1, Q2 | N1, N2 | Good via SCA |
| T1014 | eBPF rootkit load | Q3 | N3 | Partial needs kernel telemetry; pre-rootkit best |
| T1552 / T1539 | Cred/env/wallet harvest | Q4 | — | Partial needs file-access telemetry |
| T1090.003 / T1567 | Tor / temp.sh exfil | Q5 | N5 | Partial off-host best (rootkit) |
| T1195.002 (worm) | npm re-publish | Q6 | N4 | Partial npm audit primary |
| — | On-host visibility after rootkit | — | — | GAP eBPF hides artifacts — rebuild |
Validation gates: (1) confirm process/file/eBPF telemetry on dev/CI hosts + npm audit ingestion; (2) baseline legit native-module installs + eBPF-using agents (allow-list for Q3); (3) lab-test a benign package dropping a binary to node_modules/tools/setup (Q1/Q2) and a benign temp.sh upload (Q5); (4) promote Q1/Q3 + the asteroiddao SCA gate; treat any confirmed host as rootkitted (rebuild).
Hunt Summary Ticket
TITLE: Hunt — IronWorm (Rust npm supply-chain worm; eBPF rootkit; Tor C2)
SEVERITY: Critical (kernel rootkit; credential + wallet theft; self-propagating)
SCOPE: Developer workstations + CI/CD runners (esp. Web3/crypto) using asteroiddao deps
HYPOTHESIS: Trojanized npm package -> install hook drops ~976KB Rust ELF (tools/setup) ->
eBPF rootkit hides it -> harvest 86 env vars/20+ cred files + Exodus seed ->
Tor /api/agent exfil (temp.sh fallback) -> re-publish via stolen npm tokens.
QUERIES RUN: Q1 hook -> native exec | Q2 ELF in node_modules | Q3 eBPF load | Q4 cred harvest |
Q5 Tor/temp.sh exfil | Q6 npm re-publish
+ Native N1-N5 (SCA, ELF scan, eBPF audit, npm token audit, Tor/temp.sh egress)
DO FIRST: N1 (asteroiddao inventory) + Q1/Q3; ISOLATE + REBUILD (don't clean - rootkit)
FINDINGS: <pending analyst execution>
GAPS: eBPF hides on-host artifacts -> off-host detection + rebuild
ACTIONS: SCA hard-block asteroiddao; --ignore-scripts; restrict eBPF; egress allow-list;
scope OIDC publish; rotate all creds; move Exodus to new seed; promote Q1/Q3
OWNER: HuntPack
VERSION: v0.3 - 2026-06-12
Changelog
table() calls now carry an explicit row limit: the default is 200 and truncation is silent, so a capped result was indistinguishable from a complete one. Atomic-IOC sweeps (filters over 5+ hashes or C2 IPs) use limit=max so a wide infection is never silently under-scoped; behavioural hunts use limit=200, where exceeding the cap indicates the query needs tuning. Where present, event names that do not exist in the Falcon data model were corrected (e.g. ServiceInstalled is a Sysmon concept, not a Falcon event; ElfFileWritten is ELFFileWritten) — such queries could never return a row. No detection logic, fields, or IOCs changed.References
| Tier | Source | Used For |
|---|---|---|
| 1 | Phoenix Security — IronWorm (Rust/eBPF/Tor) | Full chain: ELF, eBPF rootkit, Tor C2, self-propagation |
| 1 | SafeDep — IronWorm campaign · OX Security — IronWorm | asteroiddao account; harvest scope; Trusted-Publishing abuse |
| 1 | BleepingComputer — IronWorm (36 packages) · The Hacker News — IronWorm & Miasma | Scope, lineage, timing |
| 2 | Cyberpress — developer-secret theft | 86 env vars, 20+ cred files, Exodus seeds, temp.sh |
HuntPack v0.3 · IronWorm · Generated 2026-06-12 · Defensive use only. The eBPF rootkit undermines on-host trust — favour off-host detection and rebuild affected hosts. Package set rotates; keep SCA + npm-token monitoring live. See the Shai-Hulud "Hades" + Mini Shai-Hulud packs for the related worm family. Validate field names in your tenant before promoting any query.