Design Partner Program
Hayrok/Resources/Blog/Research Notes
HAYROK LABS RESEARCH NOTE · HL-RN-2026-11 Vulnerability management

How to reduce vulnerability backlogs with exploitability validation.

Your backlog is mostly noise. Here is how to prove it.

Collapse CVEs into the fixes that close them, filter out code that never runs and assets nothing can reach, then validate what is left. Every row that leaves the list keeps its evidence.

Hayrok Labs Nov 4, 2026 @Melly 9 min read
ONE BACKLOG, FILTERED ILLUSTRATIVE RUN
Raw findings
4,812
Fix groups
611
Loaded at runtime
203
Reachable from an entry point
74
Hot: KEV or EPSS 0.95+
19
Validated exploitable → tickets
7
RULE Only the last row becomes engineering work. Everything else keeps its evidence and reopens on change.
TL;DR
01
Backlogs do not shrink by working harder. The median organization had 50% more critical vulnerabilities to patch this year than last.
02
Count fixes, not CVEs. Then remove what never runs, what nothing can reach and what fails validation. What remains is the real backlog.
03
Further down: a pandas script that collapses a raw export into fix groups and filters it down to tickets worth a sprint.

Backlogs grow for two boring reasons. Scanners count every vulnerable package on every asset as a separate problem, and nothing ever leaves the list without a patch. So let's treat the backlog as a measurement problem first. Collapse findings into fixes, drop what is not present or not reachable, validate the rest, and record every suppression with evidence and a trigger that brings it back. The result is a backlog that shrinks for reasons you can defend, and stays small.

Key findings

MORE CRITICALS THAN LAST YEAR
+50%
The median organization had 50% more critical vulnerabilities to patch than the year before. Backlogs are growing faster than teams.
KEV INSTANCES STILL OPEN AT DAY 28
35%
Even known exploited bugs linger. More than a third were still open four weeks after discovery.
CVES MOVED TO "NOT SCHEDULED"
~29,000
NIST shelved unenriched CVEs in April 2026, so less of your backlog arrives with NVD context.
VULNERABILITIES ACTUALLY REACHABLE
~3%
When Snyk tested reachability on Java Maven projects, only around 3% of vulnerabilities found were reachable from application code.
The backlog is not a to-do list. It is an inventory, and most of the inventory is not exposure.

Why backlogs only grow

None of these are anyone's fault. They are what happens when the list only knows how to add.

CVE counting inflates the list

One outdated base image can produce hundreds of findings across dozens of services, all closed by one rebuild.

Nothing leaves without a patch

Without an evidence-based way to suppress, unreachable findings sit open forever and age into SLA breaches.

Scans add, nothing subtracts

Every new scanner and CVE feed adds rows. Few programs remove rows when an asset is retired or a package stops loading.

Engineering stops listening

When tickets arrive by the hundred, teams triage by ignoring them. The backlog becomes background noise.

The method: five filters, in order of cost

Cheap filters run first and remove the most rows. Only the last one becomes engineering work. Everything that exits earlier keeps its evidence and comes back on its own if the reason stops being true.

F1

Group by fix

Collapse findings into the change that closes them: a package upgrade, a base image rebuild or a configuration change. Report the backlog in fix groups, not CVEs.
Output → fix groups
F2

Filter by runtime presence

Drop fix groups whose vulnerable code is never loaded on any asset. Record the evidence and a trigger to recheck on the next deploy.
Not loaded → suppress, reopen on deploy
F3

Filter by reachability

Drop groups no realistic entry point can reach. Keep the reason, such as the network boundary or authentication layer that blocks it.
Not reachable → suppress, with the blocking control named
F4

Validate the hot remainder

Run the five-gate test from How to Validate Whether a Vulnerability Is Actually Exploitable on groups with a KEV listing or a high EPSS percentile. The verdict decides the ticket.
KEV or EPSS 0.95+ → validate
F5

Ticket by fix, suppress with triggers

Raise one ticket per fix with its proof attached. Everything else becomes a suppression record with an owner, a reason and the change events that reopen it.
Exploitable → ticket · otherwise → suppression record

Worked example: from 4,812 findings to 7 tickets

Let's run the first filters on a raw scanner export. The script needs pandas and three CSV files you probably already have: scanner findings, runtime library data from your agents or CodeFabrics, and an exposure map.

python · backlog.py
import pandas as pd

f = pd.read_csv("findings.csv")          # cve, package, fixed_in, asset
rt = pd.read_csv("runtime_loaded.csv")   # asset, package (loaded at runtime)
ex = pd.read_csv("exposure.csv")         # asset, reachable_from_entry (bool)

# 1. Group by fix: one upgrade closes every CVE it covers
f["fix"] = f["package"] + "@" + f["fixed_in"]

# 2. Runtime presence: keep findings whose package is loaded on that asset
f = f.merge(rt.assign(loaded=True), on=["asset", "package"], how="left")
f["loaded"] = f["loaded"].fillna(False)

# 3. Reachability: keep findings on assets an entry point can reach
f = f.merge(ex, on="asset", how="left")

live = f[f["loaded"] & f["reachable_from_entry"].fillna(False)]

print("raw findings      ", len(f))
print("fix groups        ", f["fix"].nunique())
print("loaded fix groups ", f[f["loaded"]]["fix"].nunique())
print("reachable groups  ", live["fix"].nunique())

Then join KEV and EPSS, as in How to Prioritize Vulnerabilities Based on Exploitability Instead of CVSS, and validate the hot groups. A typical run looks like this:

Raw findings
4,812
Fix groups
611
Loaded at runtime
203
Reachable from an entry point
74
Hot (KEV or EPSS 0.95+)
19
Validated exploitable → tickets
7
Illustrative values. Bars are log-scaled so the small stages stay visible.

Seven tickets carry proof. The other 604 fix groups do not vanish. Each one gets a suppression record like this:

yaml · suppression record (one per fix group)
fix: jackson-databind@2.15.0
reason: not_loaded
evidence: library absent from loaded classes on all 23 assets, 2026-11-04
owner: platform-team
reopen_on: [image_rebuild, dependency_change, new_kev_listing]
review_by: 2027-02-04
Now the backlog shrinks for reasons you can show an auditor, and every row comes back automatically if the reason stops being true.

How to measure the outcome

Five numbers that tell you whether the backlog is really shrinking or just being hidden.

Backlog in fix groups
Report open fix groups, not open CVEs. It is the number engineering can act on.
Evidence-backed suppression rate
The share of closed or suppressed groups with a stored reason and a reopen trigger.
Refill rate
New fix groups per week. A rising rate points at base images or dependency hygiene.
Reopen rate
Suppressions reopened by a trigger. A healthy rate shows the triggers work.
Proof coverage
The share of open tickets with a validation verdict attached.

How Hayrok approaches backlog reduction

Hayrok ingests findings from the scanners you already own and groups them by fix. Then each filter gets an engine.

CodeFabrics
Supplies runtime presence for application code.
AGIE
The Attack Graph Intelligence Engine supplies reachability from real entry points.
Validates the hot remainder through a Private Runner.
Stores every verdict and suppression with its reason and reopen triggers.
Risk Engine
Ranks the few fix groups that remain.

Engineering sees a short list of proven fixes. Security keeps a complete record of why everything else waited.

FAQ

What is the fastest way to reduce a vulnerability backlog?

Group findings by the fix that closes them, then filter out code that never runs and assets no entry point can reach. These two steps usually remove most of the list.

Is it safe to suppress vulnerabilities that are not reachable?

Yes, if the suppression stores its evidence and reopens automatically on change, such as a new deploy, a dependency change or a new KEV listing.

Should backlog SLAs count CVEs or fixes?

Fixes. One base image rebuild can close hundreds of CVEs, so counting CVEs rewards the wrong work and hides progress.

How does exploitability validation reduce a backlog?

It turns findings into verdicts. Proven findings become tickets with evidence, and disproven ones leave the queue with a record of why.

How do we stop the backlog from refilling?

Track the refill rate by source, fix base images and dependency hygiene upstream, and revalidate on change instead of rescanning everything into new tickets.

Cut your backlog with evidence

Send us a scanner export. We will show how many fix groups it really holds, and which few are proven exploitable.

KEEP READING