Safeguard
Open Source Security

What is npm Security

A concrete look at npm security: real 2025 supply chain attacks on chalk and debug, the Shai-Hulud worm, and how teams actually defend the npm dependency tree.

Priya Mehta
DevSecOps Engineer
8 min read

Every week, developers pull down more than 40 billion package downloads from the npm registry — the default dependency manager for practically every JavaScript and Node.js project on earth. That scale is exactly why npm has become one of the most attacked links in the software supply chain: compromise a single maintainer account or slip a malicious postinstall script into a popular package, and you inherit access to millions of downstream machines, CI pipelines, and crypto wallets. npm security is the set of practices, tooling, and registry-level controls used to prevent that — covering package integrity, maintainer account takeover, dependency confusion, and malicious code hidden in install scripts or transitive dependencies. In 2025 alone, attackers hijacked maintainer accounts behind chalk, debug, and eslint-config-prettier — packages with a combined multi-billion weekly download footprint — proving that even "boring," heavily-vetted utility libraries are viable attack vectors. This glossary post breaks down what npm security actually means, the incidents that shaped it, and how teams defend against it.

What Is npm Security?

npm security is the discipline of protecting the install, build, and runtime supply chain that flows through the npm registry and CLI. That includes verifying package integrity (via lockfile hashes and Sigstore-based provenance), controlling who can publish under a package name, auditing transitive dependencies for known CVEs, and restricting what arbitrary code — like preinstall and postinstall lifecycle scripts — is allowed to execute on a developer's machine or CI runner during npm install. Because a single package.json can pull in hundreds of transitive dependencies the developer never directly reviewed, npm security also extends to software composition analysis (SCA): continuously inventorying every package in a dependency tree and flagging the ones with known vulnerabilities, malware, or license risk. The npm registry itself has grown to more than 3.5 million published packages as of 2025, making it the largest single collection of open source code in existence — and the largest attack surface tied to any one package manager.

What Are the Most Common npm Attack Vectors?

The most common npm attack vectors are maintainer account takeover, malicious lifecycle scripts, typosquatting, and dependency confusion. Account takeover — usually via phishing — lets an attacker publish a malicious version of a package that already has an established trust relationship with millions of installs, which is exactly what happened to ua-parser-js on October 22, 2021, when versions 0.7.29, 0.8.0, and 1.0.0 were hijacked to drop cryptomining and password-stealing malware onto an install base of roughly 7 million weekly downloads. Malicious postinstall scripts abuse the fact that npm executes arbitrary shell commands at install time by default; this is how the July 2025 compromise of eslint-config-prettier delivered a Windows-targeted backdoor to anyone who ran npm install before the malicious versions were pulled. Typosquatting relies on names like reactjs or crossenv sitting one keystroke away from legitimate packages, banking on developer typos or copy-paste errors. Dependency confusion exploits internal package names that mirror public ones, tricking build systems into pulling an attacker-controlled public package instead of the private one a company intended.

How Did the September 2025 npm Attacks on chalk and debug Actually Work?

The September 2025 attack worked through a targeted phishing email that impersonated npm support and tricked maintainer Josh Junon (npm handle "qix") into handing over publishing credentials for chalk, debug, ansi-styles, strip-ansi, color-convert, supports-color, and several other foundational packages with a combined weekly download count in the billions. The attacker published trojanized versions containing an in-browser crypto-clipper that silently rewrote cryptocurrency wallet addresses in transaction data, aiming to redirect funds without triggering any obvious application errors. Because these packages sit deep in the transitive dependency tree of an enormous share of the JavaScript ecosystem — many developers had never heard of ansi-styles despite running it daily — the blast radius was determined not by direct installs but by how many other packages depended on them. Within the same month, a separate self-propagating worm dubbed "Shai-Hulud" compromised more than 500 npm packages by using stolen publishing tokens to inject a payload that ran TruffleHog against local environments, exfiltrated discovered secrets to attacker-controlled GitHub repositories, and then used any harvested npm tokens to republish itself into still more packages — a genuinely self-replicating supply chain worm, not just a one-off malicious payload.

How Many npm Packages Actually Contain Known Vulnerabilities?

A meaningful share of the registry carries known, exploitable vulnerabilities, and the count of outright malicious packages has been rising sharply year over year. Sonatype's State of the Software Supply Chain research recorded roughly 245,000 malicious open source packages discovered across registries in 2023 — a jump of over 200% from the prior year — and open source intelligence vendors have continued to report six-figure counts of newly identified malicious packages annually since. Separately, because a typical Node.js project pulls in dozens of transitive dependencies for every package listed directly in package.json, a vulnerability disclosed in one low-level utility (such as the event-stream backdoor discovered in November 2018, which hid a targeted cryptocurrency-wallet-stealing payload inside the flatmap-stream sub-dependency) can silently affect thousands of downstream applications that never explicitly chose to install it. This transitive exposure is why point-in-time npm audit scans routinely surface vulnerabilities in packages a development team didn't know it was running at all.

How Can Teams Secure Their npm Dependencies?

Teams secure npm dependencies by combining registry-level controls with pipeline-level scanning and enforcement. That starts with committing package-lock.json (or npm-shrinkwrap.json) so every install resolves to the exact same, previously-vetted version and hash rather than a version range that could resolve to a newly-compromised release. It continues with enabling npm's provenance attestations — introduced in npm CLI 9.5 in April 2023 and built on Sigstore's Fulcio and Rekor transparency log — which let consumers verify that a published package was actually built from the source repository and CI workflow it claims to come from. npm itself began requiring two-factor authentication for maintainers of the top 100 highest-impact packages in 2022 (later expanded to the top 500) directly in response to the event-stream and ua-parser-js incidents, and organizations should mirror that by enforcing 2FA and short-lived, scoped publishing tokens for their own npm accounts rather than long-lived credentials. Finally, restricting or auditing lifecycle scripts — many teams now run npm install --ignore-scripts by default in CI and allowlist only the packages that legitimately need a build step — closes off the single most common execution vector for install-time malware.

What Role Does an SBOM Play in npm Security?

A software bill of materials (SBOM) plays the role of ground truth: it's the authoritative, machine-readable inventory of every package, version, and transitive dependency actually shipping in an application, which is what makes rapid incident response possible when a package like chalk or debug turns out to be compromised. Without an SBOM, answering "are we affected?" during an active npm supply chain incident means manually grepping package-lock.json files across every repository and every deployed artifact — a process that can take days precisely when speed matters most. With a current SBOM in CycloneDX or SPDX format, that same question is a lookup: search for the compromised package name and version range across every generated SBOM and get a definitive list of affected services in minutes. That's why SBOM generation is increasingly treated as a build-pipeline requirement rather than a compliance checkbox, particularly for teams subject to frameworks that reference NIST SP 800-218 (SSDF) or executive-order-driven federal software supply chain requirements.

How Safeguard Helps

Safeguard closes the gap between "a vulnerable or malicious npm package exists somewhere in our dependency tree" and "here's exactly what to fix, and how urgently." Our reachability analysis traces whether a vulnerable function in a compromised package like chalk, debug, or a typosquatted dependency is actually called from your application's code paths, so security teams can triage the small set of genuinely exploitable findings instead of chasing every CVE in a lockfile. Griffin AI, Safeguard's security reasoning engine, correlates that reachability signal with maintainer-account risk, publish-time anomalies, and known malicious-package indicators to flag npm supply chain incidents — including account-takeover-style compromises — as they emerge, not weeks later. Safeguard generates and ingests SBOMs automatically across your build pipeline, giving you the searchable inventory needed to answer "are we affected?" within minutes of a disclosure like the September 2025 chalk/debug incident. And where a fix is available, Safeguard opens auto-fix pull requests that bump the affected package to a patched, verified version, cutting remediation from a multi-day ticket queue down to a single review-and-merge.

Never miss an update

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