Safeguard
Open Source Security

State of npm supply chain attacks

Maintainer phishing, self-propagating worms, and mass-download packages compromised: a look at the npm supply chain attack trends reshaping open source risk.

Safeguard Research Team
Research
7 min read

The npm registry logged another turbulent year. Between the self-propagating "Shai-Hulud" worm that hit hundreds of packages in late 2025, a wave of maintainer-account phishing that compromised some of the most-downloaded utility libraries in the JavaScript ecosystem, and a steady drumbeat of typosquatting and dependency-confusion campaigns, the npm ecosystem has cemented its status as the software supply chain's most contested battleground. For security teams, the question is no longer whether npm will be targeted again — it's how fast the next compromise will propagate through their build pipelines before anyone notices.

This report pulls together the major campaigns, the attacker techniques that are proving most effective, and the structural reasons npm keeps winning attackers' attention — followed by what defenders can actually do about it.

The Numbers: A Year of Escalation

Malicious package volume on npm has not leveled off — it has compounded. Automated scanners publishing to the registry, combined with a long tail of copy-paste typosquats, mean thousands of malicious or suspicious packages are identified and removed from npm annually, a figure that has grown year over year since researchers began systematically tracking it around 2020. What's changed more recently isn't just volume; it's blast radius. Where early npm attacks targeted obscure or low-download packages hoping to catch a handful of unlucky installs, the campaigns defining 2025 targeted packages with tens or hundreds of millions of weekly downloads — chalk, debug, ansi-styles, strip-ansi, and other deeply nested transitive dependencies that sit invisibly inside nearly every modern JavaScript build.

The September 2025 npm compromise is the clearest illustration. A maintainer behind several foundational terminal-styling and logging packages was phished via a fake npmjs.com support email, giving attackers publish rights to packages that collectively account for a significant share of all npm downloads. The injected payload was a browser-based crypto-clipper designed to intercept wallet transactions — a narrow monetization goal riding on an enormous distribution footprint. Because these packages are dependencies of dependencies, most consuming organizations had no direct import statement to grep for, no obvious signal in a package.json diff, and no way to know they were affected without dependency-tree-aware tooling.

Weeks later, the "Shai-Hulud" incident demonstrated a more dangerous pattern: self-propagation. Rather than a single injected payload, the malware harvested credentials from CI environments (npm tokens, GitHub tokens, cloud credentials) and used them to automatically publish trojanized versions of other packages the compromised maintainer had access to — a worm that spread laterally across the registry without further attacker interaction. Security researchers tracking the campaign counted hundreds of affected packages within days, a scale that would have been implausible in a manually-operated campaign.

Anatomy of the Attack Techniques

Four techniques dominate the current npm threat landscape, and they are increasingly used in combination rather than isolation:

Maintainer account takeover. Phishing remains the highest-leverage entry point because a single compromised credential grants publish access to every package that maintainer owns — instantly weaponizing whatever download count that package has accumulated over years of legitimate use. Attackers have shown a clear preference for targeting maintainers of small, widely-depended-upon "leaf" utility packages precisely because they receive less security scrutiny than flagship frameworks, yet appear in an outsized share of dependency trees.

Self-propagating credential harvesting. The Shai-Hulud pattern — steal CI/CD and registry tokens from an infected build, then use them to infect the next package — turns every insecure CI runner into an amplifier. This is a meaningful escalation from earlier "protestware" incidents like node-ipc in 2022, which sabotaged systems geolocated to specific countries but did not spread on its own.

Typosquatting and brandjacking. Packages with names one keystroke away from popular libraries (or matching internal/private package names companies haven't registered publicly — dependency confusion) continue to appear in bulk, betting on developer typos and misconfigured registry resolution order rather than sophisticated intrusion.

Post-install script abuse. npm's preinstall/postinstall lifecycle hooks remain the most common execution vector because they run automatically, with no user interaction, the moment npm install completes — often inside a CI runner that already holds cloud credentials, signing keys, or production secrets. This was the mechanism behind both the 2021 coa/rc hijacking and numerous 2025 incidents.

Why npm Remains the Preferred Target

npm's threat model is shaped by three structural facts that are unlikely to change soon. First, scale: npm hosts more packages than any other language registry, and the JavaScript ecosystem's culture of granular, single-purpose micro-packages means a typical production application pulls in hundreds of transitive dependencies its developers have never heard of, let alone reviewed. Second, trust inheritance: a compromise of one popular leaf package instantly compromises every package — and every application — that depends on it, with no additional attacker effort. Third, weak default provenance: while npm has rolled out supply-chain security features like package provenance attestations and 2FA requirements for high-download maintainers, adoption is uneven, and a large share of the registry's most-depended-upon packages still lack cryptographic proof of who published what, from where, and how.

The economics also favor attackers. A single successful compromise of a package with 50 million weekly downloads reaches more endpoints in a day than most targeted phishing campaigns could reach in years — and it does so with the implicit trust developers extend to anything already listed in their lockfile.

The Detection Gap

The recurring failure mode across nearly every incident above is the same: organizations discover they were affected only after public disclosure, community chatter, or a vendor advisory — not through their own monitoring. Three gaps drive this:

  • Lockfiles create false confidence. A pinned version in package-lock.json feels safe, but if that version was the malicious one at the time of install, pinning simply locked in the compromise.
  • SBOMs, where they exist, are static snapshots. An SBOM generated at build time doesn't tell you that a dependency you shipped six months ago was retroactively flagged as malicious last week.
  • Most orgs can't answer "are we exploitable," only "are we present." Knowing a compromised package is somewhere in the dependency tree is very different from knowing whether the vulnerable or malicious code path is actually reachable and executed in your application.

What Security Teams Should Do Now

Effective defense against this trend requires moving past periodic dependency audits toward continuous, reachability-aware monitoring:

  1. Pin and verify, don't just pin. Lockfiles should be paired with continuous re-verification against threat intelligence feeds, not treated as a one-time control.
  2. Restrict lifecycle scripts in CI. Running npm install --ignore-scripts where feasible, and sandboxing build environments so a compromised postinstall script can't reach registry tokens or cloud credentials, meaningfully shrinks the self-propagation blast radius.
  3. Maintain a living SBOM, not a point-in-time one. Software Bills of Materials need to be continuously ingested and re-checked against emerging malicious-package intelligence, not filed away after a release.
  4. Prioritize by reachability, not just presence. With thousands of alerts possible across a large dependency tree, teams need to know which flagged packages are actually invoked by running code versus sitting dormant and unreachable.
  5. Automate the fix, not just the alert. Given how fast these campaigns move — Shai-Hulud infected new packages within hours of the initial compromise — manual triage-and-patch cycles are too slow. Auto-remediation needs to be part of the response loop.

How Safeguard Helps

Safeguard is built for exactly this threat pattern. Our reachability analysis goes beyond "is this malicious package in my tree" to determine whether the flagged code path is actually invoked by your application at runtime, letting security teams cut through alert noise from mass-compromise events like the September 2025 npm incident and focus on what's truly exploitable. Griffin AI, Safeguard's detection engine, continuously correlates newly disclosed malicious packages and worm-like propagation patterns against your live dependency graph, so you learn about exposure from us — not from a public disclosure days later. Our SBOM generation and ingestion pipeline keeps your bill of materials current and continuously re-checked against emerging threat intelligence, replacing the static, point-in-time snapshot most teams rely on today. And when a compromised or malicious dependency is confirmed, Safeguard can open an auto-fix pull request that pins to a clean version and updates the lockfile, cutting the window between disclosure and remediation from days to minutes. As npm supply chain attacks continue to grow in scale and speed, that combination of reachability-first triage and automated response is what keeps a registry-wide incident from becoming an organizational one.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.