Shai-Hulud 2.0: DevOps Supply-Chain Nightmare
Late November 2025 brought a wave of supply-chain chaos that felt different from earlier NPM incidents. This time the attacker didn’t simply sneak malicious code into a handful of packages and wait — they designed a worm that weaponized developer workflows, CI/CD, and token reuse to turn every compromised maintainer into an active amplifier. The result: hundreds of trojanized packages, tens of thousands of attacker repos, and a multi-cloud credential harvest on an industrial scale.
This is a hybrid account — a short narrative of how the campaign played out, and a practical technical breakdown for defenders.
Morning: the developer who did nothing wrong
Imagine a mid-level engineer opening their laptop to run npm install for a project. The dependency tree pulls in an innocuous package used widely across teams — a package that, earlier that week, had been silently pushed to a malicious version by an attacker who controlled a maintainer account. During installation, before any tests run and before CI artifacts are built, a tiny preinstall script executes and the machine is quietly enlisted into the campaign.
That preinstall hook loads a small runner (setup_bun.js) which then executes the main payload (bun_environment.js). Within minutes the payload has scraped local credentials, checked for CI environment variables, and attempted to reuse any tokens it finds. If tokens exist, it enumerates repositories the identity can access and republishes infected package versions or creates exfiltration repos containing harvested secrets. If no tokens are found, some samples pivot to destructive behavior — wiping files or deleting directories — and elsewhere the worm attempts privilege escalation via Docker and sudoers tampering.
Technical anatomy (what made 2.0 worse)
Propagation vector. The campaign shifted from postinstall to preinstall, dramatically increasing the blast radius. Preinstall runs earlier and is more likely to execute on CI runners and developer machines.
Core payload files.Two loader/payload files were widely observed:
- setup_bun.js — loader/initialization.
- bun_environment.js — payload that harvests credentials, injects workflows, republishes packages.
CI & GitHub Actions abuse. The worm automatically writes malicious GitHub Actions workflows into repos. One persistent backdoor was a discussion workflow injected via the GitHub API — it registers a self-hosted runner and allows arbitrary commands to be executed by posting repository discussions. Example of the API call attackers used to add the workflow:
The workflow becomes a remote command channel: open a discussion, trigger the runner, execute code.
Credential theft and cross-victim exfiltration. Harvest targets included npm tokens, GitHub PATs, SSH keys, and cloud credentials (local SDK files and metadata APIs). Stolen credentials were used instantly to publish new malicious package versions and to create public repos that held victims’ secrets — sometimes publishing one victim’s data from another victim’s account (cross-victim exfiltration).
Scale and impact. Research vendors observed ~700 malicious package versions and tens of thousands (reported 25k+) attacker repositories. Popular libraries in the blast radius included packages linked to AsyncAPI, PostHog, Postman, Zapier and others — putting a massive portion of developer ecosystems at risk.
Why containment is a race against time
This worm is fast. Stolen tokens are reused within minutes to republish packages and inject workflows. Preinstall execution means CI builds are infected before tests or scanning finishes. That makes early detection and immediate secret rotation critical; delay equals amplification.
Practical defensive playbook (short & urgent)
- Rotate everything now — revoke npm tokens, GitHub PATs, SSH keys, and cloud credentials for any identity that built or installed packages since Nov 21, 2025. Use short-lived, scoped tokens going forward.
- Rebuild CI runners from clean images — destroy and recreate any self-hosted runners; rotate runner tokens.
- Harden lifecycle scripts — block or audit preinstall/postinstall hooks in CI and reject packages with unexpected lifecycle scripts.
- Search & remove attacker artifacts — scan your orgs for new repos with “Sha1-Hulud” descriptions, unexpected workflow files, or suspicious branches; remove attacker repos and artifacts.
- Pin dependencies to verified versions or roll back to known good lockfiles until packages are confirmed clean.
- Limit outbound egress from build hosts — restrict network access from CI to a small allowlist of hosts.
- Monitor for indicators — unexpected PUT /contents calls, new workflows, npm published by your org’s maintainers, and artifacts that include cloud.json, truffleSecrets.json, or other exfil files.
- Include package managers and CI in your threat model — treat them as first-class attack surface items and run tabletop exercises for supply-chain worm scenarios.
Closing — a simple, hard lesson
Shai-Hulud 2.0 turned routine development and automation into the attack surface. Its speed and automation make it closer to a biological worm than to a targeted breach — and the only effective defenses are fast rotation, strict token practices, hardened CI, and better visibility into lifecycle scripts and automated publishes.

Centralise your Appsec
A single dashboard for visibility, collaboration, and control across your AppSec lifecycle.
Explore Live Demo