Only 7.5% of CVEs are expressible in package coordinates
Package scanners aren't missing KEV by accident. KEV-with-ransomware is structurally less package-representable than the baseline corpus.
The standard read on CISA KEV — the catalog of CVEs attackers are actively using — is that it's a "what's exploitable" signal that should bias your remediation queue. The implicit assumption is that the KEV-listed CVEs lean toward the same population as the CVEs your scanner can find: open-source libraries with version ranges, packaged through PyPI / npm / Maven / etc.
That assumption is wrong. After reconciling 6.1M records across 40 sources into 337,516 canonical CVEs, 7.51% of all CVEs are package-representable — meaning at least one of their alias-graph rows ships a version range in one of the 8 v1 language ecosystems (PyPI, npm, Maven, Go, crates.io, RubyGems, NuGet, Packagist). KEV's rate is 7.35%. KEV-with-known-ransomware-use drops to 4.36%. The KEV-and-not-EPSS-p95 slice — the bugs CISA flagged but exploit-prediction missed — is 1.87%.
The intuition that KEV is "the package-vulnerability-rich subset" is the opposite of what the data shows. KEV is a system-software catalog. The package-scanner blind spot isn't an oversight; it's a structural property of which CVEs land in which detection-modality universe.
This post defines representability formally, walks the 5-bucket source-presence taxonomy that breaks the 337k-CVE corpus into mutually-exclusive populations, and shows the cross-tab against KEV / EPSS / ransomware that makes the structural mismatch concrete.

Defining representability
A CVE is package-representable iff:
at least one of its alias-graph rows carries a non-empty
rangesJSON in one of the 8 v1 language ecosystems
This is operationally what an SBOM scanner needs. Without a (package, version-range) pair in those feeds, the scanner can't match against an installed version no matter how clever the matching logic on top. "Representable" is the necessary precondition; "actionable" (representable AND a fixed event published) is the sufficient one. We'll get to the actionability gap in a moment.
The 5-bucket taxonomy refines the binary representable/not into mutually-exclusive populations, priority-ordered richest-to-poorest:
| Bucket | Definition | Share of CVE corpus |
|---|---|---|
| PACKAGE_RANGE | Has a version range in one of 8 language ecosystems. Matcher can answer "am I affected at version X?". | 7.51% (25,352) |
| PACKAGE_ADVISORY | Has a curated advisory record (ghsa-reviewed / pypa / rustsec / go-vulndb / osv-{8 ecos}) but no source ships a range. | 0.09% (293) |
| DISTRO | Curated only in OSV's distro buckets (Debian/Ubuntu/Alpine/RPM-based/Wolfi/Chainguard/MinimOS). | 0.00% (1) |
| UNREVIEWED_MIRROR | Only in ghsa-unreviewed and/or osv-GIT / osv-Linux / osv-Bitnami / etc. — essentially CVE-Project passthroughs ingested without curation. | 88.15% (297,534) |
| CVE_ONLY | Only in cve-project / cisa-kev / epss. No advisory feed (curated or mirror) ships any record. | 4.25% (14,336) |
Two surprising things about the corpus topology:
-
Curated public OSS vulnerability intelligence covers about 7.6% of CVEs. PACKAGE_RANGE + PACKAGE_ADVISORY + DISTRO totals 25,646 CVEs out of 337,516. The other 92% is split between raw NVD passthroughs (88%) and CVEs that no advisory feed touches at all (4%).
-
The "everything is in OSV / GHSA" intuition is technically true but misleading. OSV's per-ecosystem buckets and
ghsa-unreviewedcollectively mirror almost the entire CVE Project — but for 88% of the corpus, that "mirror" is a CVE description without package-version semantics. There's no fix-version intelligence for a scanner to match against.
The cross-tab that tells the structural story
Take the 5-bucket population and cross-tab against KEV, EPSS p95+, and the ransomware sub-cohort:
| Cohort | n | PACKAGE_RANGE | UNREVIEWED_MIRROR | CVE_ONLY |
|---|---|---|---|---|
| All CVEs in corpus | 337,516 | 7.51% | 88.15% | 4.25% |
| KEV (any CISA-listed) | 1,592 | 7.35% | 90.58% | 1.95% |
| KEV ∩ ransomware | 321 | 4.36% | 95.02% | 0.62% |
| EPSS p95+ (top 5% likely-exploit) | 16,306 | 8.45% | 88.97% | 2.51% |
| EPSS p99+ (top 1%) | 3,264 | 15.75% | 83.27% | 0.92% |
| KEV − EPSS p95+ (KEV the model missed) | 480 | 1.87% | 91.46% | 6.67% |
| EPSS p95+ − KEV (predicted but not listed) | 15,194 | 8.36% | 88.92% | 2.72% |
A few things to chew on:
KEV's representability rate matches the global corpus. 7.35% vs 7.51%. KEV isn't biased toward package-representable CVEs. Reading KEV as a "this is what your scanner should catch" signal misses the structural fact that the catalog mostly lists operational software — Exchange Server, Cisco IOS XE, F5 BIG-IP, Ivanti Connect Secure, Fortinet, Apple iOS kernel, Windows Win32k.
KEV with known ransomware use is actively less representable than baseline. 4.36% vs 7.51%. Ransomware operators picked their targets from the less package-scanner-visible end of the catalog. That makes sense if you imagine where ransomware lives operationally: VPN gateways, file-transfer appliances, virtualization stacks, Exchange. Not npm packages.
The KEV-that-EPSS-missed slice is 1.87% representable. Of the 480 CVEs where CISA said "this is exploited" but EPSS didn't flag it as likely-exploit, only 9 are expressible in package coordinates. The remaining 471 are operational software CISA learned about via exploitation reports rather than via probabilistic-exploit modeling. This is the cohort where conventional scanner+EPSS pipelines fail the hardest — because both signals are looking at a population the bugs aren't in.
The EPSS p99+ cohort is the only one meaningfully skewed toward representability. 15.75% vs 7.51% baseline. The top 1% of EPSS — the model's "imminent exploitation" calls — does lean toward libraries, possibly because the model sees more historical exploit data for OSS supply-chain incidents than for appliance firmware.
What lives in the CVE_ONLY bucket
The 4.25% of CVEs that no advisory feed (curated or mirror) covers at all is operationally the most interesting bucket. These are pure CVE-Project / KEV / EPSS records — the CVE exists, NVD knows about it, but no downstream feed has ingested it yet.
For the 31 KEV CVEs in this bucket (CVE_ONLY ∩ KEV), the top vendors are:
| Vendor | Count |
|---|---|
| Apple | 9 |
| Microsoft | 4 |
| FreePBX | 2 |
| 2 | |
| Adobe / Progress Software / Palo Alto Networks / Erlang / WebPros / metabase | 1 each |
These are very recent KEV additions where the CVE-Project record hasn't propagated to ghsa-unreviewed or osv-GIT yet. Even the mirror lag matters operationally: if you're trying to act on a KEV addition within hours of CISA's announcement, the downstream feeds may not have ingested the corresponding CVE description yet, so a scanner that only queries OSV/GHSA will return nothing.
Two related metrics: actionability and timing
Representability is a necessary condition for SBOM matching. Two follow-on metrics tighten the operational picture.
Actionability = representable AND at least one source ships a fixed event. An advisory that says "vulnerable starting at 1.0" with no upper bound is representable (a matcher can say "you're affected") but not actionable (a matcher can't tell the user which version to upgrade to).
| Population | Representable | Actionable | Action / Repr |
|---|---|---|---|
| All CVEs | 25,352 | 21,535 | 84.9% |
| KEV | 117 | 111 | 94.9% |
| KEV ∩ ransomware | 14 | 13 | 92.9% |
| EPSS p99+ | 514 | 463 | 90.1% |
15% of representable CVEs lack a published fix. The KEV and EPSS cohorts have slightly higher action-given-repr rates than the corpus baseline — when the exploitation signals fire, the curated feeds usually have also shipped a fix, which is the rare bit of good news in the data.
Timing lag — how long from CVE publication to first-seen-in-source — is even harsher:
| Pair | n | Median lag | p95 lag |
|---|---|---|---|
| CVE Project → first OSV ecosystem entry | 25,099 | 0 days | 1,998 days (5.5 yr) |
| CVE Project → ghsa-reviewed | 24,988 | 1 day | 2,414 days (6.6 yr) |
| CVE Project → CISA KEV | 1,592 | 322 days | 3,487 days (9.5 yr) |
| GHSA-reviewed → OSV ecosystem | 24,892 | 0 days | 0 days |
KEV is a heavily lagging signal. Half of KEV-listed CVEs are added to the catalog 11 months after their CVE date. The p95 is 9.5 years. 770 of the 1,592 KEV CVEs (48%) were added more than a year after CVE publication; 293 (18%) were added more than 5 years later. Treating KEV as a real-time "exploitable today" feed underestimates how much attacker activity is on old, recently-resurfaced CVEs.
Compare that to GHSA → OSV-ecosystem, which has a p95 lag of literally 0 days. The OSV-ecosystem buckets pull GHSA same-day. (This is the same redistribution-fidelity result the previous post in this series makes the load-bearing case for.)
What this implies for security tooling decisions
A few concrete consequences of taking representability seriously as a construct:
-
"My scanner missed CVE-X" is not the same as "my scanner is broken." For 92% of CVEs, missing is the only possible outcome for a package-coordinate scanner — the CVE isn't expressible in those coordinates. The operationally meaningful question is what fraction of representable CVEs your scanner is catching, not what fraction of all CVEs.
-
Stacking scanner + KEV / scanner + EPSS doesn't paper over the structural gap. The KEV-only-not-EPSS cohort, where ransomware actors disproportionately operate, is 1.87% representable. Adding KEV to a package-scanner pipeline catches roughly 9 of the 480 in that slice.
-
The non-representable population needs a different detection modality, not a better package scanner. That's the actionability gap formalized: there are two fundamentally different vulnerability universes (package-representable vs operational/system) and conflating them in tooling decisions costs operator attention.
-
For the representable slice, the matcher works. Post 3 in the series walks through
check_affected.py, which takes a CycloneDX SBOM and producesAFFECTED/NOT_AFFECTED/UNKNOWNverdicts using ecosystem-correct version comparison.
Honest limitations
-
8 ecosystems is an arbitrary boundary. Hex, Pub, Hackage, CRAN, Bioconductor, GHC, SwiftURL are also "language ecosystems" but have so little KEV/EPSS overlap that they're excluded from the v1 scope. Adding them wouldn't move the representability needle much (a few hundred CVEs at most) but it would be defensible to include them.
-
DISTRO bucket is essentially empty (n=1). Not because distros don't track CVEs — they track plenty — but because the CVEs they track are almost all also tracked by a higher-priority source (ghsa-unreviewed at minimum), so they land in a richer bucket. The 5-bucket model is priority-ordered, which makes DISTRO unreachable in practice. That's a feature, not a bug — DISTRO is the bucket-of-last-resort for "this CVE is exclusively in OSV's distro feeds", which turns out to be ~0 CVEs at corpus scale.
-
The 7.51% representability rate is a function of which ecosystems are in scope. If you redefined "representable" to include distro buckets (where
epoch:version-releasestrings are in principle comparable, just not v1-supported by the matcher), the rate would climb. But the operational consequence — that KEV-ransomware is less representable than baseline by every reasonable definition — doesn't move much.
Reproducing this
git clone https://github.com/benseverndev-oss/goldenmatch-vuln-attribution
cd goldenmatch-vuln-attribution
python sync_cloud.py
cat output/representability_taxonomy.json | jq .cohort_breakdown
cat output/actionability.json | jq .by_population
cat output/timing_lag.json | jq .summary.pairs
Or directly from the latest release without cloning:
curl -L -O https://github.com/benseverndev-oss/goldenmatch-vuln-attribution/releases/download/latest/representability_taxonomy.json
The methodology — what counts as a "curated" source, which OSV buckets count as distro vs language vs unreviewed-mirror, what the priority ordering is — is documented in docs/definitions.md and docs/annotation-protocol.md. The qualitative-validation pass (cross-model κ on a 156-CVE manual sample) hit 0.648 on representability_type and 0.737 on scanner_modality between Claude Opus 4.7 and gpt-4o-mini — substantial-agreement-band on Landis & Koch, which is the best evidence I have that the closed-enum taxonomy is operationally applicable rather than reflecting any single labeller's idiosyncrasies.
Key takeaways
- 7.51% of CVEs in the reconciled 6.1M-row, 337,516-CVE corpus are package-representable. The remaining 92% live in
UNREVIEWED_MIRROR(88%) orCVE_ONLY(4%) buckets — raw NVD passthroughs or pure metadata with no advisory feed coverage. - KEV's representability rate (7.35%) matches the global corpus. KEV is not biased toward package-scanner-visible CVEs.
- KEV-with-ransomware drops to 4.36% representable. Ransomware actors disproportionately operate in the operational/system universe.
- The KEV-that-EPSS-missed cohort is 1.87% representable. Adding KEV to a package-scanner pipeline catches 9 of 480 in that slice.
- 84.9% of representable CVEs are also actionable (have a published
fixedevent). The 15% gap is real informational asymmetry — representability is a ceiling, not a guarantee. - KEV is heavily lagging (median 322 days from CVE publish, p95 = 9.5 years).
- The cross-model κ on the closed-enum taxonomy is in the substantial-agreement band (0.648 / 0.737 between Claude and GPT), which is the strongest evidence I have that the buckets aren't arbitrary.
Where this fits in the series
This is post 2 of three on the reconciliation work. Post 1 showed that apparent cross-source remediation agreement is overwhelmingly a redistribution artifact (1,898× more disagreement in the independent pair). Post 3 — "SBOM scanning with three-state verdicts" — walks through check_affected.py, the operator-facing matcher that consumes a CycloneDX SBOM and produces per-component AFFECTED / NOT_AFFECTED / UNKNOWN verdicts with per-interval evidence.
For the original cluster-level findings (KEV blind spot, EPSS distribution, github-reviewed coverage), see the 5/15 post. For the source code and reproducibility surface: github.com/benseverndev-oss/goldenmatch-vuln-attribution.
Related posts
→ 88% of actively-exploited CVEs aren't in any package ecosystem
Re-running the OSS vuln reconciliation at 6.1M records and 40 sources surfaces a structural blind spot in every package-level scanner.
2026-05-15
→ The OSS vuln-DB 'consensus' is a redistribution artifact
Cross-source remediation agreement looks near-perfect at 99-100%. De-duplicate the mirrors and it collapses to 70%. The lift is 1,898x.
2026-05-17
→ Reconciling 15 OSS Vulnerability Databases
Cross-database ER across OSV, GHSA, PyPA, RustSec, Go vulndb — 869k records, 608k canonical vulns, and one structural blind spot.
2026-04-10