The Shai-Hulud worm has returned. Between November 21-23, 2025, the self-replicating npm malware compromised over 300 packages from Zapier, ENS Domains, PostHog, and Postman, infecting 20,000 repositories with 1,000 new infections added every 30 minutes. This is the second wave of the first successful self-propagating attack in npm history. GitHub’s September 2025 security fixes—mandatory 2FA, 7-day token expiration, trusted publishing—clearly weren’t enough.
Developers who thought they were safe after September are being reinfected. The worm has evolved with new variants targeting preinstall hooks, proving npm’s fundamental architecture remains vulnerable. On Hacker News, the story hit 284 points with 226 heated comments debating one question: Is npm fundamentally broken?
September’s Attack: The First Self-Replicating Worm
On September 15, 2025, security researchers discovered Shai-Hulud, the first self-replicating worm in npm ecosystem history. The attack compromised over 500 packages with 2 billion combined weekly downloads, including popular libraries like @ctrl/tinycolor (2.2 million weekly downloads), ngx-bootstrap (300,000 weekly), and ng2-file-upload (100,000 weekly).
The worm’s mechanism was devastatingly simple: phishing emails disguised as npm security alerts tricked developers into revealing credentials. Once inside, malware executed via postinstall hooks, harvesting npm tokens and GitHub Personal Access Tokens. Using those stolen credentials, the worm identified other packages maintained by the victim, injected malicious code, and republished new compromised versions automatically.
CISA classified it as a “Widespread Supply Chain Compromise.” GitHub announced comprehensive fixes: mandatory 2FA for publishing, granular access tokens with 7-day expiration, revoked legacy tokens, and trusted publishing for CI/CD. By mid-November 2025, the rollout was complete.
November’s Return: Evolved and Spreading
Except they didn’t fix it. Between November 21-23, Shai-Hulud came back with new variants. Wiz Research estimates over 20,000 repositories compromised across 350+ unique maintainer accounts, with 1,000 new infections appearing every 30 minutes as of November 23.
The November wave targets major companies: Zapier’s @zapier/secret-scrubber (40,000 weekly downloads), ENS Domains, PostHog, Postman, and AsyncAPI.
The worm evolved. September’s variant executed via postinstall hooks—malicious code ran after package installation completed. November’s variant moved to preinstall hooks, executing before installation finishes. That’s a wider attack surface and harder to detect or stop. New payloads appeared: setup_bun.js, bun_environment.js, and malicious discussion.yaml GitHub workflow files.
The self-replication mechanism still works. Stolen credentials still grant publishing access. The worm still spreads exponentially. Nothing fundamental changed.
Why GitHub’s Fixes Failed
GitHub’s September response looked comprehensive on paper. Mandatory 2FA should prevent unauthorized publishing. Seven-day token expiration should limit damage from stolen credentials. Trusted publishing should eliminate long-lived tokens entirely.
But here’s the problem: stolen tokens remain valid until expiration. September compromises left attacker-controlled credentials active through November—up to 90 days for some tokens. 2FA doesn’t prevent phishing, which was the initial compromise vector. Developers clicked malicious links, entered credentials, and attackers harvested tokens before 2FA even mattered.
Most critically: GitHub made no architectural changes. Lifecycle scripts still execute arbitrary code by default. Packages can still modify and republish other packages. Self-propagation mechanisms remain functional. The November wave exists as evidence—same attack vector, different timing hook.
Hacker News developers summed it up: “Band-aids, not solutions.”
What Developers Must Do Now
Security researchers are clear: “Any system that installed these versions should be treated as fully compromised.” If you installed any package updated November 21-23 from compromised maintainers, assume the worst.
Immediate actions: Pin all dependencies to versions from before November 21, 2025. Search your GitHub account for public repositories named “Shai-Hulud”—the worm creates these to dump stolen secrets. Review GitHub Actions workflows for suspicious .yaml files. Rotate every credential from a separate, trusted machine: npm tokens, GitHub Personal Access Tokens, SSH keys, AWS, GCP, and Azure credentials.
Long-term defense requires disabling lifecycle scripts. Use npm install --ignore-scripts in CI/CD pipelines. Consider migrating to package managers that disable lifecycle scripts by default—pnpm, for example. Implement strict dependency pinning and manual review before updates.
Is npm Fundamentally Broken?
September’s attack was a wake-up call. November’s return is the alarm nobody wanted to hear. The Hacker News discussion (284 points, 226 comments) captures the industry’s growing concern: maybe npm’s architecture is fundamentally broken.
The flaw is structural. npm executes arbitrary code by default during installation. No sandboxing. No isolation. Lifecycle scripts run with full system privileges. Self-propagation is possible because packages can modify and republish other packages automatically. Token-based authentication allows stolen credentials to work for days or weeks.
Other ecosystems don’t have this problem. Deno requires explicit permissions for network, file system, and environment access. pnpm disables lifecycle scripts by default. Python’s pip doesn’t auto-execute code. Rust’s Cargo sandboxes build scripts with limited capabilities.
npm chose convenience over security years ago. That choice is now enabling self-replicating worms.
Complete architectural overhaul is unlikely—too disruptive for the massive npm ecosystem. Migration to alternatives like Deno or pnpm will be slow. Incremental patches will continue. Security researchers at Unit42 called this “one of the most severe JavaScript supply-chain attacks observed to date.” It won’t be the last.
GitHub promised fixes. The worm came back anyway. Developers now face ongoing risk from self-propagating threats that exploit the very foundations of npm’s design. The industry can keep applying band-aids, or it can finally admit that npm needs fundamental rethinking. Because Shai-Hulud just proved one thing: this worm won’t die until the architecture that enables it does.










