RFX-SCI-04
Supply Chain Integrity
2024–2026

Vulnerability Data Gaps

A clean scan built on incomplete data
  • NVD enrichment backlog and unscored CVEs
  • wrong version ranges and identifiers
  • exploitation before severity scores arrive
Reconnaissance
Evaluate
Fortify
Limit
Expose
Exercise

Scenario

A platform team gates every release on its scanner. The rule is simple: fail the build on any finding with an NVD CVSS score of 7.0 or higher. The dashboard is green, and has been for weeks.

Three things are hiding behind that green:

  1. A new CVE in one of their libraries was published nine days ago. NVD has not scored it yet, so the gate ignores it.
  2. Another advisory lists affected versions only for the supported release lines. The team is on an older line, so the scanner finds no match.
  3. A third library is shaded inside a fat JAR from an internal project. Its packages were relocated and its Maven metadata dropped, so the scanner cannot identify it.

The attacker does not wait for any of this to be sorted out. They read the advisory and the fix commit, build an exploit and start scanning the internet within hours. The severity score that would have tripped the gate arrives weeks later.

Real-world precedent: NIST has carried a growing backlog of unenriched CVEs since early 2024. In April 2026 it said record enrichment of about 42,000 CVEs in 2025 still could not keep pace with submissions. It now prioritises KEV entries, software used by the US federal government and EO 14028 critical software, and has stopped routinely adding its own score when the CNA has provided one. Meanwhile, Amazon reported exploitation attempts against React2Shell (CVE-2025-55182) within hours of its disclosure on 3 December 2025.

Reconnaissance

Explanation

Attackers read the same public data you do. They simply act on it sooner. A fix commit, a release note or a GitHub advisory tells them where to look. Severity scores, affected-product data and scanner rules all arrive later.

Sonatype's 2026 State of the Software Supply Chain report measured the gap. It found NVD's median time to score 2025 open source CVEs was 41 days, and 35% took more than three months to get a complete record. Exploit proofs of concept and patches often appear within hours.

Insight

The period before a score exists is when fast action matters most. Any process that waits for NVD enrichment is blind during exactly that window.

Practical

  • Find out which data sources each of your tools uses: NVD, GitHub Advisory Database, OSV, vendor feeds or their own research.
  • Check which severity source your build gates use. If it is NVD only, unscored CVEs pass silently.
  • List the components you know are shaded, vendored or statically linked, since scanners are least reliable there.

Tools/Techniques

  • Your scanners' documentation on vulnerability sources.
  • OSV, which aggregates GitHub advisories, ecosystem databases and others in one schema.
  • The NVD record status for CVEs that affect you.

Metrics/Signal

  • Build gates that rely on a single severity source.
  • Findings in your current scans that have no NVD score.

Evaluate

Explanation

Test your vulnerability data as well as your code. Scan the same SBOM with two tools and compare. Differences come from different sources, different version-range data, different identifiers and different matching rules.

Sonatype's report gives a sense of the scale. It found about 65% of 2025 open source CVEs had no NVD CVSS score, and 46% of those were High or Critical on its own review. NVD and Sonatype severity categories agreed only 56% of the time. Sonatype reported over 20,000 false positives and 167,000 false negatives and linked them to problems such as wrong version ranges and wrong component identifiers. These are one vendor's figures. NIST's own statements on the enrichment backlog point the same way.

Insight

Two scanners disagreeing is useful evidence. Each difference is a question about scope, identification or data, and some of the answers will surprise you.

Practical

  • Scan one SBOM with Trivy and OSV-Scanner, then compare CVE IDs. OSV-Scanner reports GHSA IDs first, so normalise using each finding's aliases:
trivy sbom --scanners vuln -q -f json -o trivy.json app.cdx.json
osv-scanner scan source -L app.cdx.json --format json --output-file osv.json

jq -r '.Results[]?.Vulnerabilities[]?.VulnerabilityID' trivy.json | sort -u > trivy-ids.txt
jq -r '.results[].packages[].vulnerabilities[]
  | ([.id] + (.aliases // [])) | map(select(startswith("CVE-"))) | .[]' osv.json |
  sort -u > osv-ids.txt

comm -3 trivy-ids.txt osv-ids.txt
  • For each difference, check the advisory's affected ranges against your version, and the component identifier (purl) each tool used.
  • Scan your built artefacts as well as your SBOM, to see whether shaded or vendored code shows up.

Tools/Techniques

Metrics/Signal

  • Percentage of findings both scanners agree on.
  • Components present in the build SBOM but not detected in the artefact scan.

Fortify

Explanation

Use more than one source, and stop treating CVSS as a priority list. Severity describes a flaw's technical characteristics. Priority depends on whether it is being exploited, how likely that is, and whether the vulnerable code is reachable in your application.

Insight

CVSS, KEV and EPSS answer different questions. CVSS describes technical severity, KEV records known exploitation, and EPSS estimates the probability of exploitation activity in the next 30 days. None of them knows your application.

Practical

  • Change gates so an unscored finding means "needs triage" instead of "pass".
  • Prioritise with KEV membership, EPSS and reachability, then use CVSS as one input among several.
  • Generate the SBOM during the build, before shading, so relocated components are still recorded.
  • Record triage decisions as VEX so the next scan, and your customers, can see why a finding does not apply:
vexctl create --product="pkg:maven/com.example/portal@2.4.1" \
  --vuln="CVE-2025-64518" \
  --status="not_affected" \
  --justification="vulnerable_code_not_in_execute_path"
  • Feed those VEX documents back into scanning, for example with Trivy's --vex option.

Tools/Techniques

  • CISA KEV catalogue and its JSON feed.
  • FIRST EPSS and its API, for example https://api.first.org/data/v1/epss?cve=CVE-2025-64518.
  • Reachability tools where your ecosystem has them, such as govulncheck for Go.
  • OpenVEX and vexctl, or CycloneDX VEX.

Metrics/Signal

  • Gates that treat unscored findings as passing, trending to zero.
  • Findings with a recorded VEX decision.

Limit

Explanation

Assume the data will sometimes be late or wrong. Limit the damage by being able to answer "where do we run this?" and ship a fix within hours, without waiting for a scanner update.

Insight

If you can search your inventory for a package and version, you know you are exposed the moment an advisory appears. You do not need to wait for a score or a scanner update.

Practical

  • Keep SBOMs for everything you deploy in a searchable store, so you can query by package and version.
  • Make patch releases routine, with automated tests strong enough that a dependency bump can ship the same day.
  • Prepare compensating controls, such as WAF rules or feature flags, for the period before a fix can ship.

Tools/Techniques

  • OWASP Dependency-Track or an equivalent SBOM store.
  • Renovate or Dependabot security updates for fast, reviewed bumps.

Metrics/Signal

  • Time to answer "which services run version X?" for a named component.
  • Time from advisory publication to a deployed fix for exploited flaws.

Expose

Explanation

Watch the advisory sources directly, alongside the scanner's verdict. New advisories, KEV additions and EPSS jumps for components you run should reach the owning team whether or not a score exists.

Insight

KEV is updated often. Joining it against your own scanner output each day is cheap, and it catches exploited flaws your gates might rate low or not at all.

Practical

  • Subscribe to GitHub or OSV advisories for your key dependencies.
  • Join the KEV feed with your scanner's CVE IDs daily:
curl -s https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json |
  jq -r '.vulnerabilities[].cveID' | sort -u > kev.txt
comm -12 kev.txt trivy-ids.txt
  • Alert on findings that stay unscored for more than a few days.
  • Re-run the two-scanner comparison on a schedule and track how agreement changes.

Tools/Techniques

  • KEV JSON feed and EPSS API in a scheduled CI job.
  • GitHub Dependabot alerts or Dependency-Track notifications.

Metrics/Signal

  • KEV matches in your estate, and time to resolve each.
  • Count of unscored findings older than seven days.

Exercise

Explanation

Measure your data gaps on one real application. Compare scanners, test shaded-JAR detection and record decisions as VEX. Nothing here needs exploit code.

Insight

Teams that try this are often surprised by how many findings differ between tools. Seeing it on your own SBOM makes the point better than any report.

Practical

  1. Generate an SBOM for one service and scan it with Trivy and OSV-Scanner, as in Evaluate.
  2. Pick three findings that differ and trace each one: source, affected range, identifier or alias.
  3. Check the NVD status of every finding. Count how many have no NVD score.
  4. In a scratch project, build a fat JAR with the Maven Shade Plugin, relocating a library at a version with a known advisory. Scan the JAR with Trivy and Syft and see whether either detects it.
  5. Write a VEX statement for one finding you have triaged, and confirm the scanner honours it on the next run.

Tools/Techniques

  • Trivy, OSV-Scanner, Syft and vexctl.
  • The Maven Shade Plugin's relocations configuration in a throwaway project.

Metrics/Signal

  • Scanner agreement rate on your SBOM.
  • Whether the shaded library was detected, and by which tool.

Further Reading