The problem: everything is critical

Your scanner just finished its weekly run and reported 4,000 findings, 600 of them rated high or critical. Your patching capacity this month is maybe 80 changes. Which 80?

If your answer is "sort by CVSS, descending," you are doing what most teams do, and it is quietly failing. Roughly 6 percent of published CVEs are ever exploited in the wild, according to research behind the EPSS model. A CVSS-sorted queue makes you spend most of your capacity on vulnerabilities nobody will ever weaponize, while the mid-scored bug that ransomware crews are actively mass-exploiting waits at position 214.

Prioritization is a triangulation problem. You need three different signals, because each one answers a different question.


CVSS: how bad is it if it happens?

CVSS (Common Vulnerability Scoring System, maintained by FIRST) measures severity, not risk. The v3.1 base score is built from eight metrics: Attack Vector (AV), Attack Complexity (AC), Privileges Required (PR), User Interaction (UI), Scope (S), and the Confidentiality, Integrity, and Availability impacts (C, I, A). CVSS v4.0 refines this with an Attack Requirements (AT) metric and splits impact between the vulnerable system (VC, VI, VA) and subsequent systems (SC, SI, SA).

CVSS is useful. It tells you the theoretical blast radius: a network-reachable, no-privilege, no-interaction RCE (think Log4Shell, CVE-2021-44228, scored 10.0) is structurally worse than a local privilege escalation requiring an existing foothold.

But CVSS is context-blind by design, and the base score says nothing about whether anyone is exploiting the bug. Two failure modes follow:

  • Volume. Thousands of CVEs score 9.8 every year. A severity score with that many maximal values cannot rank a queue.
  • No exploitation signal. A 9.8 in an obscure enterprise product with no public exploit can sit unexploited for a decade. A 7.5 in an internet-facing file transfer appliance can be mass-exploited in 48 hours (MOVEit, CVE-2023-34362, started at 9.8 but the pattern holds for plenty of 7.x edge-device bugs).

Use CVSS to answer "how bad," never "how soon."


EPSS: how likely is exploitation?

EPSS (Exploit Prediction Scoring System, also maintained by FIRST) is a daily-updated machine learning model that estimates the probability that a CVE will be exploited in the wild within the next 30 days. It learns from real exploitation telemetry (honeypots, IDS sensors) correlated with vulnerability features: public exploit code, Metasploit modules, vendor, CWE class, chatter, age.

Every CVE gets a score between 0 and 1, plus a percentile. The distribution is heavily skewed: most CVEs score under 0.05, so a score of 0.30 already puts a vulnerability far into the dangerous tail.

Practical thresholds that teams use as starting points:

EPSS score Read it as Suggested handling
>= 0.5 Exploitation likely, often already observed Patch this cycle, no debate
0.1 to 0.5 Elevated, exploit tooling probably exists Patch soon if reachable
0.01 to 0.1 Background risk Normal cadence
< 0.01 Unlikely near-term Batch with routine updates

EPSS has its own blind spots: it knows nothing about your assets, it lags on brand-new CVEs until signal accumulates, and it predicts exploitation somewhere on the internet, not in your network. It is a probability, not a verdict.


KEV: is it being exploited right now?

The Known Exploited Vulnerabilities catalog, maintained by CISA since November 2021 under Binding Operational Directive 22-01, is not a prediction. It is a curated list of CVEs with reliable evidence of active exploitation in the wild, each with a required remediation due date for US federal civilian agencies.

For everyone else, KEV is the closest thing to a free, vendor-neutral "attackers are using this today" feed. The catalog holds over 1,300 entries, and the bar for inclusion is high: confirmed exploitation, an assigned CVE, and a clear remediation path.

The rule is simple: a KEV-listed vulnerability on an asset you own outranks everything that is not KEV-listed, almost regardless of CVSS score. EternalBlue (MS17-010, CVE-2017-0144) is the canonical lesson: teams that deferred a "just another SMB patch" in March 2017 met WannaCry in May.

KEV's limitation is the mirror of its strength: it is reactive. A CVE lands there only after exploitation is confirmed, which can be weeks after it started. That is exactly the gap EPSS covers.


Combining the three signals

Each score answers one question:

Signal Question answered Maintained by Updates
CVSS How severe is the impact? FIRST (spec), NVD and CNAs (scores) At publication, occasional revisions
EPSS How likely is exploitation soon? FIRST Daily
KEV Is it exploited right now? CISA Continuously

Add the fourth input the public feeds cannot give you, asset context: is the vulnerable system internet-facing, does it hold sensitive data, is it a domain controller or a lab VM?

A practical priority ladder, evaluated top-down, first match wins:

P1  (patch now, 24-72h):
    KEV-listed AND asset reachable by the relevant vector
P2  (this week):
    EPSS >= 0.5 AND CVSS >= 7.0 AND asset internet-facing
P3  (this patch cycle):
    EPSS >= 0.1 AND (CVSS >= 7.0 OR asset is crown-jewel)
P4  (normal cadence):
    CVSS >= 7.0, low EPSS, internal asset
P5  (batch or accept):
    everything else

Some teams prefer a single composite number, something like risk = EPSS x impact_weight(CVSS) x asset_criticality, with KEV as an override to the top. Both work. What matters is that exploitation evidence and probability come before raw severity, and that asset context multiplies rather than decorates.

Run the numbers on a typical month and the effect is dramatic: the "must patch now" set shrinks from 600 CVSS-criticals to a few dozen vulnerabilities, and it now contains the ones that show up in incident reports.


Making it operational

The workflow only sticks if the data is in one place. Nobody will cross-reference three websites per CVE at triage time. Options:

  • Pull the feeds yourself: NVD for CVSS, the daily EPSS CSV from FIRST, the KEV JSON from CISA, then join on CVE ID in your asset database.
  • Use a source that pre-joins them. Every entry on vuln.mlab.sh surfaces the CVSS v3.1/v4.0 vectors, the current EPSS score and percentile, and a KEV flag side by side, searchable and available through a JSON API, so a triage decision is one lookup instead of three.

Then wire the ladder into your process: KEV additions matching your stack should page the vuln management channel the same day, EPSS threshold crossings should feed a weekly review, and the CVSS-only backlog becomes what it should have been all along, routine hygiene.


CVSS tells you how hard the punch would land. EPSS tells you if a punch is coming. KEV tells you it already has. Prioritize in that order, weight by what the asset is worth, and your patch queue starts matching reality.