Shai-Hulud V2 Poses Risk To NPM Supply Chain

Shai-Hulud V2 Poses Risk To NPM Supply Chain

Shai-Hulud V2 is an advanced supply chain campaign that abused the npm ecosystem to compromise over 700 packages, create 27,000+ malicious GitHub repositories, and expose roughly 14,000 secrets across hundreds of organizations. It leverages preinstall execution, Bun-based payloads, self-hosted GitHub Actions runners, cross-victim credential recycling, and a destructive dead man’s switch to maximize persistence, propagation, and data exfiltration. #ShaiHulud #npm

Keypoints

  • Shai-Hulud V2 infected over 700 npm packages within hours and created more than 27,000 malicious GitHub repositories, exposing ~14,000 secrets across 487 organizations.
  • The campaign shifted from postinstall to preinstall lifecycle execution, allowing payload execution even when installs fail and increasing impact.
  • V2 adopts the Bun runtime with a small dropper (setup_bun.js) and a large obfuscated payload (bun_environment.js) for stealth and evasion.
  • Stolen credentials (GitHub PATs, npm tokens, cloud keys) are validated and reused to publish infected packages, create repositories, and register self-hosted GitHub Actions runners for persistence.
  • Data exfiltration is performed by uploading encoded files (contents.json, environment.json, cloud.json, truffleSecrets.json, actionsSecrets.json) to attacker-created GitHub repos to blend with legitimate traffic.
  • Cross-victim credential recycling lets the malware find tokens in previously created repos, creating a botnet-like propagation and resilience against token revocation.
  • A dead man’s switch can trigger destructive wiping (cipher/shred) if access to GitHub and npm is lost, risking mass data destruction across infected hosts.

MITRE Techniques

  • [T1195 ] Supply Chain Compromise – Compromised and published malicious updates to npm packages to propagate the malware (‘compromised over 700 npm packages’).
  • [T1059 ] Command and Scripting Interpreter – Uses JavaScript dropper and payload scripts (setup_bun.js, bun_environment.js) and executes shell commands to install runtimes and runners (‘setup_bun.js dropper script performs several functions… Launches the obfuscated payload (bun_environment.js) as a detached background process.’)
  • [T1105 ] Ingress Tool Transfer – Downloads and installs Bun and the official GitHub Actions runner to the host to enable execution and persistence (‘Downloads and installs Bun using official installers’ / ‘Downloads the official GitHub Actions runner (v2.330.0).’)
  • [T1543 ] Create or Modify System Process – Installs and starts self-hosted GitHub Actions runners (SHA1HULUD) as background processes to maintain persistent remote execution (‘Registers the runner under the name SHA1HULUD… Starts the runner as a background process.’)
  • [T1552 ] Unsecured Credentials – Harvests tokens from environment variables and files, including npm tokens in .npmrc and GitHub tokens in env vars (‘Extracts npm authentication tokens from .npmrc files.’ / ‘Searches for Personal Access Tokens (ghp_) and OAuth tokens (gho_) within environment variables.’)
  • [T1078 ] Valid Accounts – Uses stolen/validated GitHub and npm tokens to publish infected packages, create repositories, and register runners (‘publishes the infected version using the stolen token’ / ‘Creates a runner registration token via the GitHub API’).
  • [T1567 ] Exfiltration Over Web Service – Exfiltrates stolen data to attacker-controlled GitHub repositories and uploads files encoded to evade detection (‘stolen data is exfiltrated to GitHub repositories that are created using compromised tokens’).
  • [T1485 ] Data Destruction – Implements a dead man’s switch that overwrites and deletes user files using cipher (Windows) and shred (Linux/macOS) if containment is detected (‘dead man’s switch initiates data destruction across the compromised system using cipher and shred’).
  • [T1082 ] System Information Discovery – Detects CI/CD environments and collects environment variables and system metadata to drive environment-aware behavior (‘Detected via environment variables such as GITHUB_ACTIONS, BUILDKITE, CIRCLE_SHA1, CODEBUILD_BUILD_NUMBER, and PROJECT_ID.’ / ‘Complete dump of process.env, containing all environment variables.’)

Indicators of Compromise

  • [Files & directories ] Malicious payloads and workflows – setup_bun.js, bun_environment.js, .github/workflows/discussion.yaml, and exfiltrated files like cloud.json, contents.json (and other exfiltrated filenames such as environment.json, truffleSecrets.json).
  • [File hashes ] Known malicious binaries – SHA256 of setup_bun.js: a3894003ad1d293ba96d77881ccd2071446dc3f65f434669b49b3da92421901a; bun_environment.js: 62ee164b9b306250c1172583f138c9614139264f889fa99614903c12755468d0 (and 1 more bun_environment.js hash).
  • [GitHub indicators ] Repository and workflow patterns – repository description ‘Sha1-Hulud: The Second Coming.’ or ‘Sha1-Hulud: The Continued Coming’, random 18-character repository names (e.g., zl8cgwrxf1ufhiufxq), workflow path .github/workflows/discussion.yaml, and self-hosted runner name SHA1HULUD.
  • [NPM packages ] Impacted package names – examples include zapier-platform-core, @ensdomains/ensjs, posthog-js, @postman/tunnel-agent, @asyncapi/generator (and dozens of other compromised packages across the ecosystem).
  • [Artifacts & exfiltrated files ] Evidence of data theft – contents.json (system info and token metadata), environment.json (process.env dump), cloud.json (cloud secret manager data), truffleSecrets.json (TruffleHog scan results), actionsSecrets.json (GitHub Actions secrets).


Read more: https://www.zscaler.com/blogs/security-research/shai-hulud-v2-poses-risk-npm-supply-chain