Shai‑Hulud Strikes Again: How a Self‑Replicating NPM Worm Compromised Hundreds of Packages
Share this article
Shai‑Hulud Strikes Again
In the early hours of November 24, 2025, security researchers at Aikido Security discovered a fresh wave of malware spreading through the npm ecosystem. The worm, dubbed Shai‑Hulud after the giant sandworms of Dune, is a self‑replicating post‑install script that infects hundreds of packages, harvests secrets, and pushes new copies to npm and GitHub. The latest iteration, released just before npm’s December 9 token‑revocation deadline, showcases a more aggressive infection vector and a broader target list.
Attack Timeline
| Date | Milestone |
|---|---|
| Aug 27 | First S1ngularity report on nx packages |
| Sep 16 | Initial Shai‑Hulud wave (first wave) |
| Sep 18 | Follow‑up analysis of early payload |
| Nov 24 | Second wave – The Second Coming |
The timing is deliberate: npm announced that it would revoke classic tokens on December 9, leaving many developers still using legacy authentication. The attackers seized the window to inflict maximum damage before the revocation.
How the Worm Works
The core of the infection lies in a deceptively innocuous postinstall script that downloads and installs the JavaScript runtime Bun. Once Bun is available, the script executes a separate payload, bun_environment.js, which performs the following:
- Secret Harvesting – Uses TruffleHog to scan the local environment for API keys, GitHub tokens, and other credentials.
- Exfiltration – Publishes any discovered secrets to a newly created public GitHub repository named with a random string and the description "Sha1-Hulud: The Second Coming".
- Self‑Propagation – Attempts to publish new versions of the infected package to npm, leveraging stolen npm credentials to spread the worm further.
- Cleanup – If authentication fails, the script deletes all files in the user’s home directory, effectively wiping the host.
Below is a sanitized excerpt of the setup_bun.js script that initiates the infection:
async function main() {
let bunExecutable;
if (isBunOnPath()) {
bunExecutable = 'bun';
} else {
bunExecutable = await downloadAndSetupBun();
}
const environmentScript = path.join(__dirname, 'bun_environment.js');
if (fs.existsSync(environmentScript)) {
runExecutable(bunExecutable, [environmentScript]);
} else {
process.exit(0);
}
}
The bun_environment.js file contains the heavy‑lifting logic that scans for secrets and attempts to re‑publish the worm. In many compromised packages, the file is missing, limiting the attack’s reach, but the presence of setup_bun.js is sufficient to trigger the download and execution of Bun.
Affected Packages
A total of 492 packages were flagged as compromised, spanning major ecosystems:
- AsyncAPI (e.g.,
asyncapi/cli,asyncapi/diff) - Zapier (e.g.,
zapier/zapier-sdk,zapier/babel-preset-zapier) - ENS (e.g.,
ensdomains/ensjs,ensdomains/ens-contracts) - PostHog (e.g.,
posthog/cli,posthog/plugin-hello-world) - Postman (e.g.,
postman/secret-scanner-wasm,postman/csv-parse)
Each package had a new version released that included the malicious post‑install script. With 132 million monthly downloads across the ecosystem, the potential attack surface is staggering.
Impact & Detection
When a developer installs one of these packages, the worm runs silently during the installation process, before the package’s main code executes. It can therefore:
- Read and exfiltrate local secrets.
- Gain unauthorized access to code repositories, package registries, and CI/CD pipelines.
- Leverage stolen credentials to publish further malicious packages.
Detection is two‑fold:
- Audit the
postinstallscripts of all dependencies. Look for calls to external installers (e.g., Bun) or references toTruffleHog. - Search GitHub for public repositories with the description "Sha1-Hulud: The Second Coming". A recent scan uncovered 26.3 k such repositories.
Mitigation Steps for Security Teams
- Pin dependency versions and lock files; avoid
^or~ranges that allow automatic upgrades to malicious releases. - Disable or sandbox
postinstallscripts in CI environments. Use tools likesafe-chainto block untrusted packages. - Rotate all credentials (GitHub, npm, cloud, CI) immediately after detection.
- Enable MFA on all developer and registry accounts.
- Audit GitHub for stray repositories with the Shai‑Hulud description and delete or secure them.
- Leverage supply‑chain security tools (e.g., Snyk, Anchore) to monitor for anomalous package behavior.
Why It Matters
The Shai‑Hulud attack exemplifies the new era of supply‑chain threats where a single compromised package can cascade into a global breach. By exploiting the npm post‑install hook, attackers bypass traditional code‑review gates and gain deep access to developers’ environments. The timing—just before npm’s token revocation—highlights how attackers can manipulate policy windows to maximize damage.
For the broader community, this incident underscores the urgency of adopting robust dependency hygiene: pinning versions, inspecting scripts, and enforcing MFA. It also serves as a reminder that ecosystem security is only as strong as its weakest link—often the untrusted code that developers pull into their build pipelines.
Source: https://www.aikido.dev/blog/shai-hulud-strikes-again-hitting-zapier-ensdomains