We bucketed every advisory in OSV.dev's public per-ecosystem archives by its record-publication year for 11 package ecosystems, and overlaid the count of open-source, security-tagged tools per language from the analysis-tools.dev catalog. The question: is the pool of open-source tools that covers a language keeping pace with how fast advisories enter the record?
TL;DR (every number recomputes from the public archives)
- Known-vulnerability advisories entering the record grew 2.3x-6.6x over five years for most ecosystems: PHP 6.6x, Java 4.8x, .NET 4.2x, Rust 3.0x, Python 2.3x.
- The open-source tool count per language is roughly flat — it is a property of the catalog, not a curve that rises with advisory volume.
- The gap is a flow: recent years (2023-2025 average) add up to 157 new advisories per open-source tool per year for Rust, 121 for PHP, 112 for Go — against just 2-13 tools per language.
- Across the 11 ecosystems, ~4,900 new vulnerability advisories land per year, served by 42 catalogued open-source security tools.
- npm is the honest exception (0.8x): its explosive growth is in malicious-package reports, which we excluded. Counting malware, npm's raw volume is 223,802 total, 96.9% MAL-; counting real vulnerable-dependency advisories, it isn't even growing.
Growth: advisories entering the record per year
Known-vulnerability advisories (malware excluded), by publication year:
| Ecosystem (language) | 2020 | 2021 | 2022 | 2023 | 2024 | 2025 | Growth (2023-25 vs 2019-20) |
|---|---|---|---|---|---|---|---|
| Packagist (PHP) | 156 | 430 | 2,326 | 771 | 1,063 | 712 | 6.6x |
| Maven (Java) | 151 | 394 | 3,009 | 951 | 565 | 711 | 4.8x |
| NuGet (.NET) | 15 | 103 | 313 | 72 | 106 | 103 | 4.2x |
| crates.io (Rust) | 168 | 487 | 339 | 260 | 321 | 363 | 3.0x |
| PyPI (Python) | 469 | 1,417 | 1,878 | 849 | 1,020 | 1,010 | 2.3x |
| RubyGems (Ruby) | 57 | 71 | 238 | 91 | 103 | 67 | 1.5x |
| npm (JavaScript) | 934 | 597 | 669 | 400 | 436 | 632 | 0.8x |
(2026 is a partial year, inflated by an OSV ingestion wave, so we lead with complete years through 2025. Pub/Hex/Swift are omitted from the growth table — their OSV histories start ~2022 with small counts.)
The flow gap: new advisories per open-source tool, per year
Recent-years (2023-2025) average new advisories per year, against catalogued open-source tools:
| Ecosystem (language) | New advisories / yr (2023-25 avg) | Open-source tools | New advisories / tool / yr |
|---|---|---|---|
| crates.io (Rust) | 315 | 2 | 157 |
| Packagist (PHP) | 849 | 7 | 121 |
| Go | 1,342 | 12 | 112 |
| Maven (Java) | 742 | 10 | 74 |
| PyPI (Python) | 960 | 13 | 74 |
| npm (JavaScript) | 489 | 10 | 49 |
| NuGet (.NET) | 94 | 7 | 13 |
| RubyGems (Ruby) | 87 | 8 | 11 |
The thinnest-covered ecosystems face the steepest flow. Rust adds ~157 new advisories per open-source tool per year against just 2 catalogued tools; PHP ~121; Go ~112.
Why it matters
Defenders have finite triage capacity. If yearly inflow keeps climbing while the tool count per language stays flat, teams face more signal per tool and per human-hour every year. That is a structural argument for prioritization — ranking by exploitation likelihood (EPSS, CISA KEV) and reachability — rather than trying to hand-review a growing pile. This study measures the flow (how fast advisories enter each year); a companion study, The SCA Coverage Gap, measured the stock (total advisories per tool).
How it was measured (reproducible)
For each ecosystem we download OSV's all.zip, read every advisory's published RFC3339 date, bucket by 4-digit year, and exclude MAL- (malicious-package) advisories so the curve tracks vulnerable-dependency advisories, not malware reports. Tool counts are the open-source, security-tagged tools per mapped language from the analysis-tools.dev catalog.
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
echo "== $eco (vulnerability advisories by year, MAL- excluded) =="
unzip -p e.zip -x '*MAL-*' | grep -aoE '"published"[[:space:]]*:[[:space:]]*"[0-9]{4}' \
| grep -oE '[0-9]{4}$' | sort | uniq -c
done
OSV data is public (per-source CC-BY-4.0 / CC0 / MIT / Apache-2.0, with attribution to OSV.dev and the underlying advisory databases); the analysis-tools.dev catalog is MIT.
Honest limitations
OSV's published field is when an advisory entered the record, not when the vulnerability was introduced or first disclosed — so this measures advisory-publication velocity, not vulnerability incidence. Bulk imports show up as spikes (a log4j-era Java backfill in 2022, a large 2026 ingestion across ecosystems), which is why we lead with complete years through 2025 and use a 2023-2025 average for the "recent flow" figures. Tool counts reflect catalog coverage, not capability — recall/precision of any tool is out of scope, and commercial tools aren't counted. No scanner is named or scored; the tool axis is an aggregate per-language count.
Full study, the complete table (including Go, 2026 partial-year columns, and the FAQ) and the reproduction script: Advisory Growth vs. Tooling Coverage on zennoxa.com
Top comments (0)