Safeguard
Supply Chain•

OSV advisory counts overstate flaws: 44,476 records, about 32,000 clusters

PyPI has 14,533 OSV advisory records but about 7,300 distinct clusters once aliases are merged. Why database counts double count and how to dedupe.

Safeguard Security Team
4 min read

The OSV dumps for seven ecosystems hold 44,476 advisory records, but merging records that name each other as aliases leaves about 31,956 clusters. PyPI shrinks from 14,533 records to about 7,325, and Go from 9,641 to 5,262. Counting records as vulnerabilities inflates totals by up to a factor of two in some ecosystems.

Method

We downloaded the per-ecosystem OSV dumps on 19 October 2026 and set aside malware records (IDs starting MAL). For each ecosystem we linked every record to the IDs in its aliases list and merged records that share an ID, directly or through a chain. The result is a cluster count. It is an approximation: a record that lists several CVEs can pull together records that describe different flaws, and an advisory with no aliases stays alone even if a person would say it duplicates another. Treat the cluster figure as a better estimate than the record count, not as truth.

Records and clusters

EcosystemRecordsClustersRecords per cluster
PyPI14,5337,3252.0
Go9,6415,2621.8
crates.io2,9232,0151.5
npm7,8467,8311.0
Maven7,1907,1811.0
NuGet1,1831,1831.0
RubyGems1,1601,1591.0

Why some ecosystems double

PyPI has two record families for the same flaw: a PYSEC record from the PyPI advisory database (7,942 records) and a GHSA record from the GitHub advisory database (6,579). Go has the Go vulnerability database (4,632 records) next to GHSA (5,008). crates.io has RUSTSEC (1,319) next to GHSA (1,604). Records in each pair usually point at each other through the aliases field, which the OSV schema defines as the IDs of the same vulnerability in other databases.

npm, Maven, NuGet and RubyGems get nearly all their records from GitHub's database alone, so they barely shrink.

CVE aliases

Of the 44,476 records, 39,825 (89.5%) list a CVE ID as an alias. By ecosystem the share is 98% for Maven, 95% for PyPI, 93% for NuGet, 92% for Go and RubyGems, 82% for npm and only 57% for crates.io. A record with no CVE alias is not necessarily weaker, since it may be a flaw that never received a CVE. But it is where a scanner that keys only on CVE IDs will miss.

What to do about it

  1. When you count vulnerabilities for a report, merge by alias first and say how you did it.
  2. Prefer a scanner that reads OSV directly, or one that cross-references several databases, so records for one flaw are joined.
  3. When you compare two tools, compare after deduplication. One may report each flaw twice and look noisier without finding more.
  4. Track by the CVE ID when there is one, and by the most specific advisory ID when there is not.

A metric that rises because a database added a second record for each flaw is not a sign of rising risk.

Safeguard's SBOM and dependency scanning lists the components you run, and reachability analysis helps separate vulnerable code your application calls from code it does not. You can try a free scan at gold.safeguard.sh/scan.

Quick check

Why does PyPI have two records for one flaw?

Two databases publish about it: the PyPI advisory database and the GitHub advisory database. Aliases link them.

Is the cluster count exact?

No. It is an approximation, since shared aliases can merge different flaws and missing aliases can leave duplicates apart.

Sources

Last reviewed: 19 October 2026.

Never miss an update

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

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.