Malware

Hands‑on guidance to hunt, contain, and evict the ongoing Shai‑Hulud 2.0 npm supply‑chain campaign using preinstall hooks, Bun‑based load...

Shai‑Hulud 2.0: an IR playbook for the npm preinstall worm

4n6 Beat
4 min read

CERT-FR issued a bulletin on November 27, 2025 describing an active supply-chain campaign against npm packages that began on November 23, 2025, has affected 700+ packages, executes via a preinstall script to harvest secrets, self-propagate, and in some cases destroy user data; they advise hunting for bun_environment.js, auditing installed versions, temporarily freezing updates, and rotating exposed secrets. (cert.ssi.gouv.fr)

Intrusion Flow

  • Initial execution (developer laptop or CI): Compromised npm package versions add a package.json preinstall that runs setup_bun.js, which installs or locates the Bun runtime and launches a large payload bun_environment.js. (wiz.io)
  • Credential theft and exfiltration: The payload enumerates environment variables and config files and invokes TruffleHog to capture credentials, then exfiltrates to attacker-created GitHub repositories often labeled with Shai-Hulud-themed descriptions; cross-victim exfiltration has been observed. (cert.ssi.gouv.fr)
  • Persistence and remote control: The malware registers a self-hosted runner named “SHA1HULUD” and drops a .github/workflows/discussion.yaml workflow so that creating a GitHub Discussion executes arbitrary commands on the victim’s self-hosted runner; a formatter_*.yml workflow is used to collect GitHub Actions secrets into actionsSecrets.json. (wiz.io)
  • Self-replication: Stolen npm tokens and GitHub access allow the actor to publish trojanized versions of additional packages under compromised maintainers, driving rapid worm-like spread across ecosystems. (wiz.io)
  • Destructive fallback: Analyses report a “dead man’s switch” that may delete user data (e.g., the home directory) when the malware cannot exfiltrate or persist; CERT-FR also warns about possible user-data deletion. (about.gitlab.com)

Key Artifacts to Pull

  • Project and dependency state:
    • package.json, package-lock.json, yarn.lock, pnpm-lock.yaml (to diff against clean versions announced by vendors such as Postman and PostHog). (blog.postman.com)
  • On-disk indicators:
    • setup_bun.js and bun_environment.js in package tarballs or node_modules; auxiliary files cloud.json, contents.json, environment.json, truffleSecrets.json. (wiz.io)
    • Suspicious GitHub workflows: .github/workflows/discussion.yaml and formatter_*.yml. (wiz.io)
  • GitHub infrastructure state:
    • Presence of self-hosted runners named “SHA1HULUD.” Use the GitHub REST API to list runners at org/repo scope during triage. (wiz.io)
  • Package manager caches and global install context:
    • npm cache directory (default on POSIX: ~/.npm with _cacache) for corroborating when/what versions were fetched. (docs.npmjs.com)

Example triage commands (read-only where possible):