Safeguard
Open Source Security

The 4 dimensions of open-source dependency risk

Open-source risk isn't one problem — CVEs, malware, license exposure, and abandonment each fail differently, and Sonatype logged 454,600+ malicious packages in 2025 alone.

Safeguard Research Team
Research
7 min read

The modern application is mostly code nobody on the team wrote. A typical service pulls in dozens of direct dependencies and, through them, hundreds of transitive ones — packages nobody explicitly chose but that ended up in the build anyway. That indirection is where most of the risk hides: Sonatype's 2026 State of the Software Supply Chain report counted more than 454,600 newly published malicious packages in 2025 alone, pushing the cumulative known-malicious total across npm, PyPI, Maven Central, NuGet, and Hugging Face past 1.233 million. Meanwhile CVE-2024-3094 — a maximum-severity, CVSS 10.0 backdoor deliberately inserted into XZ Utils by a multi-year trusted contributor persona — showed that even a widely used, seemingly boring compression library can carry a nation-state-grade payload. These aren't the same failure mode. A known CVE, a malicious package, a copyleft license obligation, and an abandoned maintainer each break your supply chain differently, and each needs a different defense. This post walks through the four dimensions of open-source dependency risk one at a time, with the real incidents that define each category and what actually mitigates it.

What makes known-CVE risk different from the vulnerabilities you write yourself?

Known-CVE risk in dependencies is a resolution problem before it's a patching problem: you can't fix a vulnerability in code you don't know you're running. Most CVEs affecting a typical application don't live in the packages listed in package.json or requirements.txt — they live several levels deep in transitive dependencies pulled in automatically by direct ones. That's why manifest-only scanning (reading the top-level dependency list) systematically undercounts exposure, while lockfile-based resolution — parsing package-lock.json, poetry.lock, or go.sum to see exactly what version actually gets installed — catches the versions your build really ships. Even with full resolution, teams routinely accumulate hundreds of open CVE tickets against packages whose vulnerable function is never actually called at runtime, which is why prioritization signals — EPSS exploitation-probability scores and CISA's Known Exploited Vulnerabilities (KEV) catalog — matter as much as the initial match. A CVE with a KEV listing and a reachable call path is an emergency; the same CVE in unreachable, unused code is a backlog item.

How did the event-stream incident show that malicious packages don't need a technical exploit?

The 2018 event-stream npm incident showed that a malicious package can ride entirely on social trust rather than a technical flaw. A contributor using the handle "right9ctrl" spent time building credibility with the original maintainer, eventually gained publish access, and on September 9, 2018 added a new dependency, flatmap-stream, into event-stream version 3.3.6. Nearly a month later, on October 5, 2018, a flatmap-stream update — version 0.1.1 — shipped the actual malicious payload, code specifically targeting the Copay bitcoin wallet application and designed to harvest private keys from wallets holding more than 100 BTC. The package had already accumulated roughly 8 million downloads by the time it was reported on November 20, 2018, and pulled six days later — nearly two and a half months after the payload shipped (per reporting from Snyk, the npm blog, and The Register). No vulnerability scanner would have flagged it, because there was no CVE and no known-bad hash yet; the only signal was a new, unreviewed dependency added by a recently trusted maintainer.

Why does the XZ Utils backdoor matter more than a typical typosquat?

The XZ Utils backdoor, tracked as CVE-2024-3094 and rated CVSS 10.0, matters because it demonstrates trust-based maintainer takeover at a scale and patience level well beyond typosquatting or dependency confusion. Over roughly two years, a persona named "Jia Tan" contributed legitimately to the widely used xz/liblzma compression library, eventually earning co-maintainer status, before inserting an obfuscated backdoor into build scripts shipped in versions 5.6.0 and 5.6.1 (released February 2024). The backdoor modified sshd behavior on affected systems to allow attacker-controlled remote command execution. It was found almost by accident: Andres Freund, a Postgres developer, noticed SSH logins taking roughly 500 milliseconds instead of the usual 100 milliseconds, investigated the latency, and traced it to the compromised library on March 29, 2024 (as documented by Rapid7 and Akamai's incident writeups). It was caught before mass exploitation — but only because one engineer noticed a timing anomaly, not because any scanner flagged it.

What obligations does a permissive license carry that a copyleft one doesn't?

A permissive license (MIT, BSD, Apache-2.0) generally requires only attribution and carries no obligation to share your own source code, which is why it dominates enterprise allowlists. Weak copyleft licenses like LGPL and MPL only require that modifications to the licensed component itself be shared, leaving proprietary code that merely links against it untouched. Strong copyleft (GPL) can require that derivative works — code that statically links or is built as one program with the GPL component — be released under the same terms, which is a serious problem if you're shipping proprietary software. Network copyleft (AGPL, SSPL) extends that obligation to software offered as a network service, closing the loophole that let SaaS companies use GPL code internally without redistributing anything. Real-world license fields are often compound expressions rather than a single tag — SPDX syntax like MIT OR Apache-2.0 for dual-licensed packages, or GPL-2.0-only WITH Classpath-exception-2.0 for a license with a carve-out — and a policy engine has to parse those expressions correctly, not just string-match the raw license field, or it will misclassify a large share of real dependencies.

Why is an abandoned or single-maintainer package a security problem, not just a reliability one?

An abandoned or single-maintainer package is a security problem because unpatched vulnerabilities in dead code stay unpatched indefinitely, and a low "bus factor" — how many people can be hit by a bus before the project stalls — makes that abandonment more likely, not less. The clearest illustration of how much leverage a single maintainer holds is the 2016 left-pad incident: its author unpublished an 11-line npm package over an unrelated naming dispute, and because thousands of other packages depended on it directly or transitively, builds broke across the JavaScript ecosystem within hours until npm intervened. Maintenance risk isn't hypothetical scoring either — signals like commit recency, open-issue backlog, release cadence, and maintainer count are observable well before a CVE ever gets filed, and packages that go quiet on all of them are measurably more likely to carry an eventual unpatched disclosure than actively maintained peers.

How Safeguard helps

Safeguard treats these four risk categories as one connected findings model instead of four separate tools. SCA resolves your full dependency graph from lockfiles — not just manifests — and matches every component against a continuously updated CVE/GHSA database enriched with EPSS and CISA KEV, then applies reachability analysis so a vulnerable transitive dependency your code never calls doesn't rank alongside one an attacker could actually reach. Eagle, Safeguard's malware classification model, scores publishes across npm, PyPI, Maven Central, and the other package ecosystems it covers across seven indicator classes — including install-script behavior, credential-harvesting patterns, and typosquat similarity — and the Package Firewall can block a classified-malicious package inline at install time before it ever lands in your tree, the way earlier detection could have shortened the event-stream or XZ Utils exposure windows. License compliance parses full SPDX compound expressions, flags discrepancies between a package's metadata and its actual LICENSE file, and enforces allow/deny policy at CI and admission time. And because malware and secret findings are never suppressed by reachability scoring, the highest-severity supply chain risks stay visible even when the rest of your backlog is prioritized down.

Never miss an update

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