October 28, 2026
Patch This First: How to Prioritize Vulnerabilities
More than 48,000 new CVEs appeared in 2025, and attackers used a small share. Here is a repeatable way to find and fix those first.

By Peter Dunn
12 min read
- 1 Patch This First: A Practical Method for Prioritizing Vulnerabilities
- โ More than 48,000 new CVEs were published in 2025. Only a small fraction will ever be exploited. Here is a repeatable way to find the ones that matter in your environment and fix them before attackers do.
- 3 The backlog math does not work
- 4 Why severity alone fails
- 5 The four signals that matter
Patch This First: A Practical Method for Prioritizing Vulnerabilities
More than 48,000 new CVEs were published in 2025. Only a small fraction will ever be exploited. Here is a repeatable way to find the ones that matter in your environment and fix them before attackers do.
TL;DR: No team can patch everything, and severity scores alone send effort to the wrong places. A defensible prioritization method combines four signals: evidence of exploitation, likelihood of exploitation, exposure, and business impact. This article turns those signals into five priority tiers with clear deadlines, shows how to automate the scoring with public data from CISA and FIRST, explains what to do when you cannot patch, and covers how AI is shrinking the time you have to act.
The backlog math does not work
Every vulnerability management program eventually hits the same wall. The scanner finds more than the team can fix, and the gap grows every month.
The numbers explain why. According to Jerry Gamblin's annual review of CVE data, 48,185 CVEs were published in 2025, a 20.6% increase over 2024. That is roughly 132 new vulnerabilities every day. Of those, 39.4% were rated High or Critical under CVSS, which means a severity-only policy would have flagged almost 19,000 new vulnerabilities as urgent in a single year.
Attackers use far fewer. According to CISA's own catalog data, CISA added 245 vulnerabilities to its Known Exploited Vulnerabilities (KEV) catalog in 2025, bringing the total to 1,484. VulnCheck, which tracks a broader set of sources, counted 884 vulnerabilities with first-time evidence of exploitation in 2025. The two sets do not line up exactly, because many vulnerabilities exploited in 2025 had CVEs from earlier years, but the scale is clear: for every newly exploited vulnerability, about 55 new CVEs were published.
The cost of getting this wrong is rising. Verizon's 2026 Data Breach Investigations Report found that 31% of breaches began with the exploitation of a vulnerability, making it the most common way in. According to coverage of the report by SecurityWeek and SC Media, the median time from detection to full remediation grew from 32 to 43 days, and organizations fully remediated only 26% of the KEV vulnerabilities in their environments, down from 38% the year before.
The goal is not to patch more. It is to patch the right things first, and to prove that you did.
Why severity alone fails
Most organizations still prioritize by CVSS score: fix the Criticals in 15 days, the Highs in 30, and so on. The problem is that CVSS was never designed to answer the question "What should I fix first?" FIRST, which maintains the standard, states in the CVSS specification that it measures the severity of a vulnerability and should not be used alone to assess risk.
A CVSS base score describes how bad a vulnerability would be if exploited. It does not tell you whether anyone is exploiting it, whether the vulnerable system is reachable, or whether the system matters to the business. CVSS v4.0, released in November 2023, adds Threat and Environmental metric groups to address part of this, but most scanners and feeds still report only the base score.
The cost of relying on severity is measurable. When the authors of the Exploit Prediction Scoring System (EPSS) released version 4 in March 2025, they compared two strategies. Remediating every vulnerability with a CVSS score of 7 or higher required working on 50.7% of all vulnerabilities and caught 74.6% of those exploited in the following 30 days. Only 6% of that effort went to vulnerabilities that were actually exploited. Prioritizing by EPSS achieved about the same coverage while reducing the effort to 6% of vulnerabilities, with 47% of the work going to exploited vulnerabilities.
That is the core insight behind every modern prioritization method: you can cover most of the real risk with a small fraction of the work, but only if you stop sorting by severity alone.
The four signals that matter
A defensible priority decision answers four questions. Each one has a reliable source, and none is enough on its own.
Exploitation evidence is the strongest signal. The CISA KEV catalog lists vulnerabilities that have an assigned CVE ID, reliable evidence of active exploitation in the wild, and a clear remediation action. It is free, machine-readable, and updated as new exploitation is confirmed. Commercial and community feeds can add earlier or broader coverage.
Exploitation likelihood fills the gap before evidence appears. EPSS publishes a daily probability, between 0 and 1, that a CVE will see exploitation activity in the next 30 days. It is a forecast, not a fact, so treat it as a way to rank the large middle of your backlog.
Exposure asks whether an attacker can reach the vulnerable code. An internet-facing VPN gateway and an isolated lab server with the same CVE do not carry the same risk.
Impact asks what an attacker gains. A vulnerability on a domain controller, hypervisor, backup server, or edge device can lead to the entire environment. Those systems are your crown jewels, and they deserve a faster clock.
The Patch This First method
The method below turns those four signals into five priority tiers. It runs the same way every time, so two analysts looking at the same finding reach the same answer, and every decision can be explained to an auditor or an executive.
The gates are applied in order:
- Is it known to be exploited? If the CVE is in KEV or another trusted exploitation feed and the asset is exposed, it is P0. If it is exploited but the asset is internal, it is P1.
- Is exploitation likely? If the EPSS score is at or above your threshold and the asset is exposed, it is P1. If the asset is internal, it is P2. A threshold of 0.10 is a reasonable starting point; adjust it to match your team's capacity.
- Everything else with a fix is P3 and goes into the normal patch cycle.
- No fix, or formally accepted risk, is P4. Track it, apply mitigations, and review it on a schedule.
One modifier applies after the gates: a finding on a crown-jewel asset moves up one tier. An exploited vulnerability on an internal domain controller becomes P0, not P1.
Impact also decides the order of work inside each tier. Sort the findings in a tier by CVSS, using the v4.0 Threat and Environmental metrics where you have them, or by SSVC's Technical Impact rating. CVSS is a poor way to decide which tier a finding belongs in, but it is a good way to decide which P1 to fix first.
The deadlines in the table are starting points, not a standard. The P0 window is intentionally short because exploitation is already happening. If your change process cannot deliver a fix in 72 hours, the first action should be a mitigation within 24 hours, followed by the patch.
Reconcile the tiers with any deadlines you are already bound by. PCI DSS v4.0 requirement 6.3.3, for example, requires patches for critical vulnerabilities to be installed within one month of release, and US federal agencies must meet the due date that CISA assigns to each KEV entry. When an external deadline and a tier deadline differ, the stricter one wins.
The tiers also map cleanly to CISA's Stakeholder-Specific Vulnerability Categorization (SSVC), which uses four outcomes: Track, Track*, Attend, and Act. If your organization already uses SSVC, the method above is a practical way to implement it with data you can collect automatically.
Automating the scoring
None of this requires a commercial platform. KEV and EPSS are both public and machine-readable, and the logic fits in a short script. The architecture below shows where each input comes from and where the output goes.
The following Python example reads a scanner export, enriches each finding with KEV and EPSS data, assigns a tier, and writes a sorted file that can feed a ticketing system. The input file needs four columns, asset, cve, internet_facing, and crown_jewel, plus an optional cvss column that orders work within each tier. If you only want the logic, read the tier() function; the rest of the script loads and writes data.
#!/usr/bin/env python3
# Tier scanner findings with CISA KEV and FIRST EPSS data.
# Input: findings.csv with columns asset,cve,internet_facing,crown_jewel (yes/no),
# plus an optional cvss column used to order work within each tier
# Output: tiered.csv, sorted from most to least urgent
import csv
import requests
KEV_URLS = [ # CISA's feed first, then CISA's official GitHub mirror as a fallback
"https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json",
"https://raw.githubusercontent.com/cisagov/kev-data/main/known_exploited_vulnerabilities.json",
]
EPSS_URL = "https://api.first.org/data/v1/epss"
HEADERS = {"User-Agent": "vuln-prioritizer/1.0 (contact: secops@example.com)"}
EPSS_HIGH = 0.10 # starting threshold; tune it to your team's capacity
SLA = {0: "72 hours", 1: "7 days", 2: "30 days", 3: "next cycle (90 days max)"}
def get_json(url, **kwargs):
resp = requests.get(url, headers=HEADERS, timeout=30, **kwargs)
resp.raise_for_status()
return resp.json()
def load_kev():
for url in KEV_URLS:
try:
return {v["cveID"]: v for v in get_json(url)["vulnerabilities"]}
except (requests.RequestException, ValueError, KeyError) as err:
print(f"KEV source failed, trying next: {url} ({err})")
raise SystemExit("Could not load the KEV catalog. Stopping rather than under-prioritizing.")
kev = load_kev()
with open("findings.csv", newline="") as f:
rows = list(csv.DictReader(f))
cves = sorted({r["cve"] for r in rows})
epss = {}
for i in range(0, len(cves), 100): # the API accepts comma-separated batches of CVEs
data = get_json(EPSS_URL, params={"cve": ",".join(cves[i:i + 100])})["data"]
epss.update({d["cve"]: float(d["epss"]) for d in data})
def tier(r):
exploited = r["cve"] in kev
exposed = r["internet_facing"].lower() == "yes"
likely = epss.get(r["cve"], 0.0) >= EPSS_HIGH
if exploited and exposed:
t = 0
elif exploited or (likely and exposed):
t = 1
elif likely:
t = 2
else:
t = 3
if r["crown_jewel"].lower() == "yes" and t > 0:
t -= 1 # crown-jewel assets move up one tier
return t
for r in rows:
t = tier(r)
k = kev.get(r["cve"], {})
r.update(tier=f"P{t}", sla=SLA[t], epss=f"{epss.get(r['cve'], 0.0):.4f}",
kev="yes" if k else "no", kev_due=k.get("dueDate", ""),
ransomware=k.get("knownRansomwareCampaignUse", ""))
# Within a tier, higher impact (CVSS) goes first, then higher exploitation likelihood.
rows.sort(key=lambda r: (r["tier"], -float(r.get("cvss") or 0), -float(r["epss"])))
with open("tiered.csv", "w", newline="") as f:
w = csv.DictWriter(f, fieldnames=list(rows[0].keys()))
w.writeheader()
w.writerows(rows)
print(f"Wrote {len(rows)} findings to tiered.csv")#!/usr/bin/env python3
# Tier scanner findings with CISA KEV and FIRST EPSS data.
# Input: findings.csv with columns asset,cve,internet_facing,crown_jewel (yes/no),
# plus an optional cvss column used to order work within each tier
# Output: tiered.csv, sorted from most to least urgent
import csv
import requests
KEV_URLS = [ # CISA's feed first, then CISA's official GitHub mirror as a fallback
"https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json",
"https://raw.githubusercontent.com/cisagov/kev-data/main/known_exploited_vulnerabilities.json",
]
EPSS_URL = "https://api.first.org/data/v1/epss"
HEADERS = {"User-Agent": "vuln-prioritizer/1.0 (contact: secops@example.com)"}
EPSS_HIGH = 0.10 # starting threshold; tune it to your team's capacity
SLA = {0: "72 hours", 1: "7 days", 2: "30 days", 3: "next cycle (90 days max)"}
def get_json(url, **kwargs):
resp = requests.get(url, headers=HEADERS, timeout=30, **kwargs)
resp.raise_for_status()
return resp.json()
def load_kev():
for url in KEV_URLS:
try:
return {v["cveID"]: v for v in get_json(url)["vulnerabilities"]}
except (requests.RequestException, ValueError, KeyError) as err:
print(f"KEV source failed, trying next: {url} ({err})")
raise SystemExit("Could not load the KEV catalog. Stopping rather than under-prioritizing.")
kev = load_kev()
with open("findings.csv", newline="") as f:
rows = list(csv.DictReader(f))
cves = sorted({r["cve"] for r in rows})
epss = {}
for i in range(0, len(cves), 100): # the API accepts comma-separated batches of CVEs
data = get_json(EPSS_URL, params={"cve": ",".join(cves[i:i + 100])})["data"]
epss.update({d["cve"]: float(d["epss"]) for d in data})
def tier(r):
exploited = r["cve"] in kev
exposed = r["internet_facing"].lower() == "yes"
likely = epss.get(r["cve"], 0.0) >= EPSS_HIGH
if exploited and exposed:
t = 0
elif exploited or (likely and exposed):
t = 1
elif likely:
t = 2
else:
t = 3
if r["crown_jewel"].lower() == "yes" and t > 0:
t -= 1 # crown-jewel assets move up one tier
return t
for r in rows:
t = tier(r)
k = kev.get(r["cve"], {})
r.update(tier=f"P{t}", sla=SLA[t], epss=f"{epss.get(r['cve'], 0.0):.4f}",
kev="yes" if k else "no", kev_due=k.get("dueDate", ""),
ransomware=k.get("knownRansomwareCampaignUse", ""))
# Within a tier, higher impact (CVSS) goes first, then higher exploitation likelihood.
rows.sort(key=lambda r: (r["tier"], -float(r.get("cvss") or 0), -float(r["epss"])))
with open("tiered.csv", "w", newline="") as f:
w = csv.DictWriter(f, fieldnames=list(rows[0].keys()))
w.writeheader()
w.writerows(rows)
print(f"Wrote {len(rows)} findings to tiered.csv")The output includes the KEV due date and CISA's ransomware flag, which are useful context for the owner of each ticket. In production, cache the KEV file daily, store EPSS history so that you can see trends, and pull exposure and criticality from your asset inventory instead of the scanner export. The script tries CISA's feed first and falls back to CISA's official GitHub mirror. If neither is available, it stops instead of continuing, because a run without KEV data would silently under-prioritize exploited vulnerabilities.
Tiers only matter if deadlines are enforced. A simple query against your findings table shows every open item that has breached its deadline, worst first:
-- Open findings that have breached their tier deadline, worst first (PostgreSQL).
-- tier_sla holds one row per tier: ('P0', 3), ('P1', 7), ('P2', 30), ('P3', 90)
SELECT f.asset, f.cve, f.tier, f.first_seen,
CURRENT_DATE - f.first_seen AS days_open,
s.sla_days,
(CURRENT_DATE - f.first_seen) - s.sla_days AS days_overdue
FROM findings AS f
JOIN tier_sla AS s ON s.tier = f.tier
WHERE f.status = 'open'
AND CURRENT_DATE - f.first_seen > s.sla_days
ORDER BY f.tier, days_overdue DESC;-- Open findings that have breached their tier deadline, worst first (PostgreSQL).
-- tier_sla holds one row per tier: ('P0', 3), ('P1', 7), ('P2', 30), ('P3', 90)
SELECT f.asset, f.cve, f.tier, f.first_seen,
CURRENT_DATE - f.first_seen AS days_open,
s.sla_days,
(CURRENT_DATE - f.first_seen) - s.sla_days AS days_overdue
FROM findings AS f
JOIN tier_sla AS s ON s.tier = f.tier
WHERE f.status = 'open'
AND CURRENT_DATE - f.first_seen > s.sla_days
ORDER BY f.tier, days_overdue DESC;When you cannot patch
Some fixes cannot be deployed quickly. The vendor has not released one, the system cannot be restarted during business hours, or the patch breaks a critical application. A tier still has a deadline, but the action changes from "patch" to "reduce the risk until you can."
Work down the ladder from the most effective mitigation to the least. Removing exposure, such as taking a management interface off the internet, often eliminates most of the risk in minutes. Disabling the vulnerable feature or applying the vendor's workaround comes next. Compensating controls, such as WAF virtual patches or stricter segmentation, buy time but can be bypassed. Risk acceptance is a last resort, and it should always have a named owner and an expiration date.
If a vulnerability was exploited before you mitigated it, patching does not end the incident. Look for signs of compromise on the affected system, and rotate any credentials it stored or handled.
The AI angle: less time, more targets, better tools
AI is changing vulnerability prioritization in three ways.
The exploit window is collapsing. In June 2026, Anthropic reported that its Mythos Preview model built working exploits from newly published patches within hours, and concluded that "N-hour is closer to the reality" than N-day. Verizon's 2026 report reached a similar conclusion, saying AI has shrunk the defensive window from months to hours. Mandiant's M-Trends 2026 estimates that the mean time to exploit is now negative, meaning exploitation often begins before a fix is available. For P0 and P1 findings, this is the strongest argument for pre-approved emergency changes and mitigations measured in hours.
AI tools are now in the KEV catalog. Langflow, an open-source platform for building AI agents, had a missing-authentication flaw, CVE-2025-3248, that allowed unauthenticated remote code execution. It carries a CVSS score of 9.8, and CISA added it to KEV on May 5, 2025. When this article was written in October 2026, its EPSS score was 0.9999, higher than 99.98% of all scored CVEs. Agent builders, model servers, and notebook platforms are often deployed quickly by teams outside IT, so they are easy to miss in an asset inventory. If you cannot see them, you cannot prioritize them.
AI can speed up triage, but it should not set priorities. Language models are good at reading vendor advisories, extracting affected products and versions, matching them against your inventory, and drafting remediation tickets. They can also be wrong with confidence, and advisory text from outside your organization is untrusted input. Use AI to gather and summarize evidence, and keep the tier decision in deterministic logic that uses KEV, EPSS, and your asset data.
Common pitfalls
Teams that adopt risk-based prioritization tend to make the same mistakes in the first few months:
- Treating EPSS as a verdict. A low score means exploitation is unlikely in the next 30 days, not impossible. KEV evidence always overrides a low EPSS score.
- Trusting a stale inventory. Exposure and criticality drive two of the four signals. If the asset data is wrong, the tiers are wrong.
- Letting P3 grow forever. The normal cycle still needs a deadline, or the backlog becomes a list of future P0s.
- Closing tickets without verifying. Confirm the fix with a rescan or a version check before a finding counts as remediated.
Metrics that prove it works
A prioritization method is only as credible as the evidence that it reduces risk. Replace "number of vulnerabilities closed" with metrics that measure the right work being done on time.
The most important number is the time it takes to remediate exploited vulnerabilities on exposed systems. If that number is falling and P0 deadlines are being met, the program is working, even if the total backlog is still large.
A 90-day roadmap
You can stand up this method in a quarter. Start with the data you already have, then improve the accuracy of each signal.
Patch this first
The backlog will never reach zero, and it does not need to. What matters is that the small set of vulnerabilities attackers are actually using, on systems they can actually reach, gets fixed first and fast.
Check for exploitation evidence, forecast likelihood, confirm exposure, weigh impact, and enforce the deadline. Do it the same way every time, automate as much as you can, and measure what matters. That is how a vulnerability program stops chasing scores and starts reducing risk.
Key takeaways
- About 55 new CVEs are published for every newly exploited vulnerability, so severity-only policies waste most of their effort.
- Prioritize with four signals: exploitation evidence (KEV), exploitation likelihood (EPSS), exposure, and asset impact.
- Use tiers with explicit deadlines, and move crown-jewel assets up one tier.
- Automate enrichment with public KEV and EPSS data, and track deadline breaches weekly.
- When you cannot patch, remove exposure first, and give every risk acceptance an owner and an expiration date.
- Let AI gather evidence, but keep priority decisions in deterministic, auditable logic.
References
- CISA: Known Exploited Vulnerabilities catalog
- CISA: KEV data files and schema (GitHub)
- CISA: Stakeholder-Specific Vulnerability Categorization (SSVC)
- FIRST: Exploit Prediction Scoring System (EPSS)
- FIRST: Common Vulnerability Scoring System v4.0
- FIRST: CVSS v3.1 specification document
- Empirical Security: Introducing EPSS version 4 (March 2025)
- Verizon: 2026 Data Breach Investigations Report
- SecurityWeek: Verizon DBIR 2026, exploitation overtakes credential theft
- SC Media: Verizon DBIR 2026, patching coverage falls
- Google Cloud (Mandiant): M-Trends 2026
- VulnCheck: State of Exploitation 2026
- Jerry Gamblin: 2025 CVE data review
- SecurityWeek: CISA KEV catalog expanded 20% in 2025
- Anthropic: Measuring LLMs' impact on N-day exploits (June 2026)
- Help Net Security: Langflow CVE-2025-3248 exploited (May 2025)
Figures are drawn from vendor, government, and research publications and may be revised. Deadlines and thresholds are suggested starting points. Code examples are illustrative; adapt them to your environment and test them before relying on them.
If you found this useful, follow me for more on vulnerability management and AI-era threats, and share it with the person who owns your patching backlog.