The SCA Coverage Gap: Where Dependency-Vulnerability Volume Piles Up vs. Where Open-Source Tooling Is Thin
We counted every advisory in OSV.dev's public per-ecosystem archives and joined it to the open-source, security-tagged scanners in the analysis-tools.dev catalog. Advisory volume and open-source tool availability are only weakly aligned: Rust (crates.io) carries 2,663 real advisories against 2 catalogued open-source tools, while Dart (Pub) and Elixir (Hex) have advisory volume but zero. A reproducible map of the 'SCA deserts.'
TL;DR — We counted the advisories in OSV.dev's public per-ecosystem archives for 11 package ecosystems, and joined them to the open-source, security-tagged tools in the analysis-tools.dev catalog (grouped by the ecosystem's language). Two things fall out. First, advisory counts need a health warning: npm's raw OSV total is 223,802, but 96.9% of those are malicious-package advisories, not vulnerable versions of legitimate packages — its real vulnerability-advisory count is 6,998. Second, once you compare like for like, advisory volume and open-source tool availability barely line up. Rust (crates.io) carries 2,663 vulnerability advisories against 2 catalogued open-source security tools — ~1,332 advisories per tool, the widest gap of any tool-served ecosystem. Dart (Pub) and Elixir (Hex) carry advisory volume but zero catalogued open-source security tools. Every number below is reproducible from two free, directly-downloadable datasets.
Why measure this
Software Composition Analysis (SCA) — finding known-vulnerable dependencies — only helps in the ecosystems a tool actually supports. The security conversation usually counts scanners or counts CVEs, but rarely puts the two side by side, per ecosystem. Yet the two quantities answer different questions:
- Advisory volume = how much known-vulnerability signal exists in an ecosystem.
- Open-source tool count = how much freely-available capacity to find it is catalogued.
Where a lot of the first meets little of the second, more of that risk goes unscanned by any open-source tool — an "SCA desert." That mismatch is a structural, public fact about the open-source security ecosystem, independent of any product. This study measures it and publishes the method so anyone can re-run it.
The measurement honesty problem: not all "advisories" are the same
OSV's bulk archives are the cleanest public source of per-ecosystem advisory counts — one
JSON file per advisory, countable with unzip -l. But two ecosystems' totals are dominated
by malicious-package advisories (IDs prefixed MAL-): reports of packages that are
themselves malware, a different risk class from "a vulnerable version of a legitimate
dependency." Reporting the raw total without splitting these out would badly mislead:
| Ecosystem | OSV total | Malicious (MAL-) |
Real vuln advisories |
|---|---|---|---|
| npm | 223,802 | 216,804 (96.9%) | 6,998 |
| RubyGems | 4,640 | 3,512 (75.7%) | 1,128 |
| PyPI | 24,570 | 11,578 (47.1%) | 12,992 |
| NuGet | 1,862 | 777 (41.7%) | 1,085 |
| (all others) | — | <20 total | ~unchanged |
So npm — which looks like the most dangerous ecosystem by an order of magnitude — has a
vulnerability-advisory count (6,998) comparable to Java or Go. Every ratio below uses the
real vulnerability-advisory count (OSV total minus MAL-), like-for-like across
ecosystems.
The coverage map
Vulnerability advisories vs. catalogued open-source, security-tagged tools for the mapped language, ranked by advisories-per-tool (higher = thinner coverage):
| Ecosystem (language) | Vuln advisories | Advisory share | Open-source tools | Advisories / tool |
|---|---|---|---|---|
| crates.io (Rust) | 2,663 | 5.6% | 2 | 1,332 |
| PyPI (Python) | 12,992 | 27.4% | 13 | 999 |
| Packagist (PHP) | 6,851 | 14.4% | 7 | 979 |
| Go (Go) | 8,577 | 18.1% | 12 | 715 |
| npm (JavaScript) | 6,998 | 14.8% | 10 | 700 |
| Maven (Java) | 6,859 | 14.5% | 10 | 686 |
| NuGet (.NET) | 1,085 | 2.3% | 7 | 155 |
| RubyGems (Ruby) | 1,128 | 2.4% | 8 | 141 |
| SwiftURL (Swift) | 62 | 0.1% | 4 | 16 |
| Pub (Dart) | 13 | 0.0% | 0 | no OSS tool |
| Hex (Elixir) | 194 | 0.4% | 0 | no OSS tool |
Snapshot 2026-07-28. Tool counts are catalogued open-source, security-tagged tools whose
language tags include the ecosystem's mapped language (an explicit modeling choice, below).
Totals across the 11 ecosystems: 47,422 vulnerability advisories, 42 open-source
security-tagged tools.
What the shape says
- Advisory volume and tool count are only weakly aligned. The highest-volume ecosystems (Python, Go) are not the most tool-thin, and the thinnest (Rust) is mid-volume. Counting scanners alone — as scanner-census work does — understates where the coverage gap actually falls, because it never weighs the volume each tool has to cover.
- Rust is the widest tool-served gap: 2,663 real advisories, 2 catalogued open-source tools. PHP and Python follow (≈1,000 advisories per open-source tool).
- Two ecosystems have no catalogued open-source security tool at all. Dart (Pub) and Elixir (Hex) each carry advisory volume that no catalogued open-source tool is recorded to scan. We report this as "no catalogued OSS tool," not as a division by zero.
- The npm paradox: by raw OSV count npm dwarfs everything, but that's the malicious-package feed. Its vulnerability coverage ratio (700 advisories/tool) is unremarkable — a caution against reading raw advisory totals as risk.
How this ties to prioritization (category-level, honest)
This is a neutral, public backdrop — not a product claim. But it explains why two things matter for anyone doing dependency security:
- Ecosystem breadth. Because vulnerability volume concentrates in specific ecosystems and open-source tool coverage per ecosystem is uneven, a single generalist tool or a DIY stack is most likely to leave the thin ecosystems (Rust, PHP, Dart, Elixir) unscanned. Breadth toward exactly those ecosystems is where added SCA coverage has the most marginal value.
- Prioritization over raw volume. Even the "real" advisory counts are large relative to any team's triage capacity. Which is the argument for ranking findings by exploitation signal (EPSS, CISA KEV) and reachability — see our companion studies on the Priority Engine — rather than simply surfacing more.
Limitations & honest caveats
- OSV bulk counts include withdrawn advisories and grow daily; two runs on different dates will differ. We print the snapshot date and reproduction commands rather than freeze a number.
- The ecosystem→language map is a modeling assumption, not a fact: npm→JavaScript(+TypeScript),
PyPI→Python, Maven→Java, Go→Go, RubyGems→Ruby, crates.io→Rust, NuGet→C#/.NET, Packagist→PHP,
Pub→Dart, Hex→Elixir/Erlang, SwiftURL→Swift. A tool that covers a language but isn't in the
catalog, or isn't
security-tagged, isn't counted — this measures catalogued open-source capacity, not all tooling that exists (commercial tools are out of scope by design). - "Malicious" vs "vulnerability" is OSV's own
MAL-prefix. We split on it rather than editorialize.
Reproduce it yourself
# Advisory counts (one JSON per advisory in each ecosystem's archive):
for eco in npm PyPI Maven Go RubyGems crates.io NuGet Packagist Pub Hex SwiftURL; do
curl -s "https://osv-vulnerabilities.storage.googleapis.com/$eco/all.zip" -o e.zip
total=$(unzip -l e.zip | grep -c '\.json$')
mal=$(unzip -l e.zip | grep -c 'MAL-')
echo "$eco total=$total malicious=$mal vuln=$((total-mal))"; rm e.zip
done
# Open-source, security-tagged tools per language:
curl -s https://raw.githubusercontent.com/analysis-tools-dev/static-analysis/master/data/api/tools.json \
| jq '[.[] | select((.other // []) | index("security")) | select((.licenses // []) | any(ascii_downcase | contains("proprietary")) | not)]'
OSV.dev data is public; the GitHub Advisory Database upstream is CC-BY-4.0 (attribution); the analysis-tools.dev catalog is MIT. No scanner is named or scored anywhere in this study — the tool axis is an aggregate count grouped by license and language.
FAQ
Does a high advisories-per-tool ratio mean an ecosystem is "insecure"? No. It means known vulnerability signal is high relative to catalogued open-source scanning capacity — a statement about tooling availability, not about the language's safety.
Why is npm not at the top despite 223,802 advisories? Because 96.9% of those are
malicious-package (MAL-) reports, a different risk class. Its vulnerability-advisory count is
6,998.
Where does Shield fit? Shield's SCA covers npm, PyPI, RubyGems, Go and Maven and has been expanding toward the thin ecosystems this map identifies (crates.io, Packagist, NuGet, plus Dart/Pub and Elixir/Hex). This study is the neutral backdrop for why that breadth matters — not a claim that Shield is the only or best option.