Advisory Growth vs. Tooling Coverage: The Capacity Gap Is a Flow, Not Just a Stock
We bucketed every OSV.dev advisory by its record-publication year for 11 package ecosystems and overlaid the count of catalogued open-source security tools per language. Known-vulnerability advisories entering the public record grew 2.3x-6.6x over five years for most ecosystems, and recent years add hundreds to thousands per ecosystem against 2-13 open-source tools — up to 157 new advisories per tool per year for Rust. A reproducible measure of whether tooling capacity keeps pace with advisory inflow.
TL;DR — We bucketed every advisory in OSV.dev's public per-ecosystem archives
by its record-publication year for 11 package ecosystems, split out malicious-package (MAL-)
reports, and overlaid the count of open-source, security-tagged tools per language from the
analysis-tools.dev catalog. Two things: known-vulnerability advisories
entering the public record grew 2.3×–6.6× over five years for most ecosystems (PHP 6.6×, Java
4.8×, .NET 4.2×, Rust 3.0×, Python 2.3×), while the open-source tool count per language is roughly
flat. And the gap is a flow: recent years (2023–2025 average) add hundreds to thousands of new
advisories per ecosystem — up to 157 new advisories per open-source tool per year for Rust, 121
for PHP, 112 for Go — against 2–13 tools. ~4,900 new vulnerability advisories land per year across
these 11 ecosystems, served by 42 catalogued open-source security tools. Every number is
recomputable from the public archives. (Important caveat: OSV published is a record-entry date, so
this measures publication velocity, not vulnerability incidence — read the method.)
Why measure this
Defenders have finite triage capacity. Our companion study, The SCA Coverage Gap, measured the stock — total advisories per open-source tool per ecosystem. This one measures the flow: how fast advisories enter the record each year, and whether the pool of open-source tools that covers a language keeps pace. If yearly inflow keeps climbing while tool count stays flat, teams face more signal per tool and per human-hour every year — which is a structural argument for triage (ranking what to fix first) over simply scanning more. We don't assert the direction in advance; we publish the computation and let the curves speak.
Method — and the one caveat that matters
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 catalog (same method as the stock study).
The caveat, stated up front, not buried: OSV's published field is when an advisory entered the
record, not when the vulnerability was introduced or even first disclosed. So this measures
advisory-publication velocity, not vulnerability incidence. Bulk imports show up as spikes — e.g.
a log4j-era Java backfill in 2022, and a large 2026 ingestion across several ecosystems. We therefore
lead with complete years (through 2025) and mark 2026 as partial, and we use a 2023–2025 average
for the "recent flow" figures rather than any single spiky year.
Growth: advisories entering the record per year
Known-vulnerability advisories (malware excluded), by publication year:
| Ecosystem (language) | 2020 | 2021 | 2022 | 2023 | 2024 | 2025 | 2026* | Growth (2023-25 vs 2019-20) |
|---|---|---|---|---|---|---|---|---|
| Packagist (PHP) | 156 | 430 | 2,326 | 771 | 1,063 | 712 | 1,255 | 6.6× |
| Maven (Java) | 151 | 394 | 3,009 | 951 | 565 | 711 | 666 | 4.8× |
| NuGet (.NET) | 15 | 103 | 313 | 72 | 106 | 103 | 311 | 4.2× |
| crates.io (Rust) | 168 | 487 | 339 | 260 | 321 | 363 | 649 | 3.0× |
| PyPI (Python) | 469 | 1,417 | 1,878 | 849 | 1,020 | 1,010 | 5,162 | 2.3× |
| RubyGems (Ruby) | 57 | 71 | 238 | 91 | 103 | 67 | 159 | 1.5× |
| npm (JavaScript) | 934 | 597 | 669 | 400 | 436 | 632 | 2,610 | 0.8× |
| Go | 0 | 375 | 927 | 639 | 1,961 | 1,425 | 3,250 | — (DB since 2021) |
*2026 is a partial year and is inflated by an OSV ingestion wave; it is shown for transparency, not trend. Pub/Hex/Swift omitted from the growth table (their OSV histories start ~2022 with small counts).
npm is the honest exception: its vulnerability-advisory flow is flat-to-declining (0.8×) — but
that's because npm's explosive growth is in malicious-package reports, which we excluded. Counting
malware, npm's raw advisory volume dwarfs everything (223,802 total, 96.9% MAL-); counting real
vulnerable-dependency advisories, it isn't even growing.
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 |
| Pub (Dart) | 3 | 0 | no OSS tool |
| Hex (Elixir) | 8 | 0 | no OSS tool |
Across the 11 ecosystems, ~4,900 new vulnerability advisories enter the record per year, against 42 catalogued open-source security tools.
What the numbers say
- Advisory publication grew multi-fold for most ecosystems over five years — 6.6× (PHP), 4.8× (Java), 4.2× (.NET), 3.0× (Rust), 2.3× (Python). The record is getting denser, not sparser.
- Tool count per language is flat — it's a property of the catalog, not a curve that rises with advisory volume — so the inflow per tool rises with the advisory curve.
- The thinnest-covered ecosystems face the steepest flow: Rust adds ~157 new advisories per open-source tool per year, PHP ~121, Go ~112 — the same ecosystems the stock study flagged as deserts.
- Malware vs. vulnerabilities are different stories: npm's real-vulnerability flow is flat once
MAL-reports are excluded, even though its raw total is the largest by far.
How this ties to prioritization (category-level, honest)
Neutral, public backdrop — not a product claim. But it's the evidence for a precondition: when the volume of security signal grows faster than the capacity to act on it, the scalable response is prioritization — ranking by exploitation likelihood (EPSS, CISA KEV) and reachability — rather than adding raw scan volume. The reader draws that conclusion from the public curves; it isn't baked into the data. And it's the same reproducibility discipline we hold ourselves to: this whole computation reruns from a pinned OSV snapshot and catalog commit, the way every Shield number reruns from a benchmark.json.
Limitations & honest caveats
- Publication velocity ≠ incidence. OSV
publishedis a record-entry date; bulk imports create spikes (2022 Java, 2026 across several ecosystems). We lead with complete years and a 2023–2025 average for exactly this reason. - Tool counts reflect catalog coverage, not capability — recall or precision of any tool is out of scope, and commercial tools aren't counted (this measures catalogued open-source capacity).
MAL-split is OSV's own prefix; we exclude malware reports from the vulnerability curves and say so.- OSV
all.ziparchives can lag the per-object listing (OSV issue #2575), but the large gaps are in OS/distro ecosystems, which this study excludes; the language package ecosystems reconcile cleanly.
Reproduce it yourself
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
rm e.zip
done
OSV data is public (per-source CC-BY-4.0 / CC0 / MIT / Apache-2.0 — attribution to OSV.dev and the underlying advisory databases); the analysis-tools.dev catalog is MIT. No scanner is named or scored — the tool axis is an aggregate per-language count.
FAQ
Is vulnerability incidence actually rising, or just OSV's coverage? This measures the record — advisories entering OSV per year. Growing coverage is part of the signal (more of the ecosystem is now catalogued), and that's exactly what a defender's triage queue sees. We flag the distinction rather than claim underlying incidence.
Why is npm's curve flat when everyone says npm is the most dangerous? npm's raw OSV total is huge,
but 96.9% are malicious-package (MAL-) reports. Its real vulnerable-dependency advisory flow, which
this study isolates, is flat-to-declining.
Where does Shield fit? It doesn't drive the study — the point is category-level: advisory inflow outpaces catalogued open-source tooling per language, which is the case for prioritizing by exploitability over scanning more.