Togoder security

Threats

Protecting against Shai-Hulud-style npm worms

Shai-Hulud was a self-replicating npm worm: an install script stole developers' and CI systems' secrets, then used stolen npm tokens to publish infected versions of the victims' own packages. To protect against it and its successors, stop dependency install scripts from running by default, delay adopting brand-new versions, scan lockfile changes, and lock down publishing with 2FA and trusted publishing.

Threats2 min readUpdated By Togoder Security

Key takeaways

  • The first wave (September 2025) ran a payload from a postinstall script; the second (November 2025) used a preinstall script. Both stole secrets and republished packages with stolen npm tokens.
  • Stolen secrets were dumped into public GitHub repositories, which is how many victims found out.
  • Disabling dependency install scripts would have stopped the payload from running on install.
  • A minimum release age of a few days avoids most worm versions, which are usually removed quickly.
  • Maintainers: use trusted publishing or short-lived granular tokens and 2FA, so a stolen token cannot republish your packages.

What happened

In September 2025 researchers found a worm spreading through npm, named after the "Shai-Hulud" repositories it created. Infected versions ran a script at install time that searched the machine for secrets (npm tokens, GitHub tokens and cloud credentials, using the TruffleHog secret scanner among other methods) and published them to a public GitHub repository under the victim's account. With a stolen npm token it then published new, infected versions of other packages that token could publish, which is what made it a worm. Hundreds of packages were affected, including some widely used ones.

A second wave in November 2025, dubbed "Sha1-Hulud: The Second Coming", used a preinstall script that installed the Bun runtime and ran a large obfuscated payload with it, again stealing secrets and republishing packages, at a larger scale. Security vendors reported that in some cases it tried to destroy files in the user's home directory when it could not steal credentials.

In response, GitHub announced changes to npm publishing, moving maintainers toward trusted publishing and short-lived, granular tokens.

The same malware family returned in 2026: its largest wave, ChainDrop (August 2026), started from the keyv maintainer's GitHub account and reached more than 400 packages, as described in the worm section of our 2024 to 2026 timeline.

If you install packages

  1. Do not run dependency install scripts by default. npm config set ignore-scripts true, enableScripts: false in Yarn, or pnpm 10 / Bun, which only run scripts of packages you allow. Both waves executed from install scripts. See detecting malicious postinstall scripts.
  2. Install from the lockfile. Use npm ci in CI so a newly published version cannot slip in through a version range.
  3. Wait before adopting new versions. Worm versions are usually unpublished within hours or days. Recent pnpm and Yarn releases support a minimum release age; Renovate and Dependabot can delay update PRs.
  4. Review what changed when the lockfile changes. Run npm audit for reported versions and scan the changed lockfile for unreported ones. A script that downloads a secret scanner or a new runtime and talks to the GitHub API is the kind of behavior an AI source review is built to flag.
  5. Limit what an install can steal. Keep long-lived tokens out of developer environment variables and CI jobs that install dependencies; use short-lived credentials.

If you publish packages

  • Publish from CI with trusted publishing (OIDC) instead of long-lived npm tokens, and remove tokens you no longer need.
  • Require 2FA for publishing on your account and packages.
  • Watch for versions you did not publish: npm view your-package time --json.

Check whether you were affected

  • Compare your lockfiles' history against the published lists of compromised versions from security vendors and the GitHub Advisory Database (npm audit flags them now).
  • Look in your GitHub account and organizations for repositories or branches you did not create and for unfamiliar workflow files under .github/workflows.
  • If an infected version was installed anywhere, rotate every secret that machine or CI job could read: npm, GitHub, cloud and API keys.

Frequently asked questions

How do I protect against npm supply chain attacks like the Shai-Hulud worm?

Disable dependency install scripts by default, install from a committed lockfile with npm ci, wait a few days before adopting new versions, scan lockfile changes for malicious code, and as a maintainer publish with trusted publishing and 2FA instead of long-lived tokens.

Would npm audit have caught Shai-Hulud?

Only after advisories for the infected versions were published. In the first hours, tools that read the install script's code were the only automated way to notice it.