Safeguard
Supply Chain Attacks

Software supply chain attack trends: what the public incident data shows

Sonatype tracked 454,648 new malicious packages in 2025 alone — over 1.2 million total since it started counting. Here's what three years of incident data reveal.

Safeguard Research Team
Research
7 min read

On March 29, 2024, PostgreSQL developer Andres Freund noticed something odd: SSH logins on a Debian test system were taking about half a second longer than they should. That anomaly led him to CVE-2024-3094, a backdoor hidden inside xz-utils versions 5.6.0 and 5.6.1 — a compression library linked into sshd on most major Linux distributions. The attacker, operating under the alias "Jia Tan," had spent roughly two to three years building commit history and maintainer trust before slipping the payload into the project's autotools build scripts in February 2024, where it evaded ordinary source review because it only materialized at build time. It remains the most sophisticated open-source build-system compromise on record, and it is also, statistically, the exception. Sonatype's 2025 State of the Software Supply Chain report counted 454,648 new malicious packages published in 2025 alone, pushing its cumulative tracked total past 1.233 million — and found that over 99% of that malicious activity happened on npm, with roughly 55.9% of logged malicious packages showing signs of registry-automation abuse rather than hand-crafted social engineering. The public data describes two very different threat models sharing one label. This piece separates them.

What does the volume data actually say about attacker behavior?

The volume data says most supply-chain attacks are automated, not artisanal. Sonatype's 2025 count of 454,648 new malicious packages in a single year, against a cumulative total of 1.233 million since it began tracking, only makes sense if a large share of that output comes from scripted, bulk publishing rather than individually crafted campaigns — which is exactly what Sonatype's finding that 55.9% of logged malicious packages show registry- or publishing-automation abuse patterns indicates. npm's open registration model, its lack of a waiting period before a new package is installable, and its enormous 3-million-plus package corpus make it the cheapest surface to spray typosquats and lookalikes at scale, which is consistent with Sonatype's finding that over 99% of open-source malware activity by volume concentrates there. This is a distribution-cost story: an attacker can automate publishing thousands of near-duplicate package names for a few dollars of compute, so the base rate of "some junk in the registry" trends upward every year almost independent of any single actor's sophistication.

How does typosquatting actually work, and why is it so hard to fully stop?

Typosquatting works by registering a package name close enough to a popular one — reqeusts for requests, a transposed character, a missing hyphen — that a developer's typo, or a copy-paste error from a phishing tutorial, installs the attacker's package instead. It is cheap because registries generally don't require proof of intent to publish a similar name, and because most ecosystems resolve package names by exact string match with no built-in "did you mean" friction at install time. It is hard to fully stop because the attack scales with the size of the ecosystem it targets — every popular package is a target, and defenders would need to preemptively register every plausible misspelling of every popular name to close the gap entirely, which no registry does exhaustively. Detection instead relies on edit-distance scoring against top-package lists combined with metadata signals — a newly published name, a different publisher than the legitimate package, thin version history — the same signal set Safeguard's Eagle classifier scores under its typosquat-similarity and metadata-anomaly indicators before a package ever reaches a developer's machine.

What is dependency confusion, and is it still a live technique?

Dependency confusion exploits how package managers resolve a name that exists both in an organization's private registry and on the public registry: many build configurations, if not pinned to an explicit internal source, will fetch whichever version number is highest — and an attacker who publishes a public package under your internal library's exact name, with a deliberately inflated version, can win that resolution. Security researcher Alex Birsan demonstrated this technique in 2021 by uploading impostor packages matching internal library names at more than 30 companies, collecting over $130,000 in bug bounties from firms that confirmed their internal builds pulled the public version automatically. It is still a live technique today precisely because the underlying resolution ambiguity is a configuration default, not a bug that gets patched once — any organization that hasn't explicitly scoped its package manager to a private registry namespace, or reserved its internal names on the public registry as placeholders, remains exposed to the identical mechanism five years later.

What made the XZ Utils backdoor different from a typical malicious-package incident?

The XZ Utils backdoor was different because it targeted trust in a legitimate, long-running project rather than impersonating one. Instead of publishing a lookalike package, the operator behind "Jia Tan" contributed real, useful patches to xz-utils for roughly two years, was granted co-maintainer access, and then used that access to commit build-script changes — hidden in M4 macros and a corrupted test file — that only assembled the malicious payload during the library's own build process, not when anyone read the source on GitHub. That is a build-system compromise, the rarest and highest-impact category in the public incident record, alongside the 2020 SolarWinds Orion compromise (the "Sunburst" backdoor, inserted into a signed build pipeline and distributed to roughly 18,000 downstream customers via routine software updates). Both cases evaded code review by design: the malicious logic didn't exist in a form a human reviewer would ever see, only in what the build tooling produced. Freund found the xz backdoor by profiling unrelated performance regressions — not through any static scan.

Do these incidents cluster into a small number of patterns?

Yes — the public record clusters cleanly into three durable patterns with very different cost-to-impact ratios. Typosquatting is cheap, high-volume, and automatable, matching Sonatype's registry-abuse data; it catches careless installs but rarely compromises a specific, chosen target. Dependency and namespace confusion exploits a structural resolution ambiguity that persists until an organization explicitly fixes its build configuration, as Birsan's 2021 research and its repeated rediscovery since show. Build-system and maintainer compromise — XZ Utils, SolarWinds, and the 2018 event-stream npm incident in which an attacker gained maintainer access via a handoff and injected a cryptocurrency-wallet-stealing dependency — is the rarest category but produces the highest-severity outcomes, because it inserts malicious code into artifacts that already carry earned trust and wide distribution. Defending against all three requires different controls: registry-level detection for the first, build-configuration hygiene for the second, and provenance/build-attestation plus anomaly detection for the third.

How Safeguard helps

Safeguard maps controls to each of these three clusters rather than treating "supply chain risk" as one bucket. The Package Firewall runs as an install-time proxy in front of npm and pip, catching typosquats and dependency/namespace-confusion attempts — including transitive fetches — before a package ever lands on disk, with audit, warn, block, and quarantine modes so teams can baseline before enforcing. Behind it, the Eagle classification model scores every artifact across install-script behavior, obfuscation, egress patterns, credential harvesting, typosquat similarity, and metadata anomalies, and retroactively re-scores the entire historical corpus whenever its model improves — so a package that looked benign at install time gets flagged the moment a new signal implicates it, the same category of delayed discovery that made XZ Utils and event-stream so damaging in the first place.

Never miss an update

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