BlogSecurity Research

CVSS vs EPSS vs CISA KEV: A Practical Comparison

Every vulnerability scan produces three numbers that look like they measure the same thing and don't: a CVSS score, an EPSS score, and a yes/no answer on whether the CVE is in the CISA KEV catalog. Teams that only look at CVSS end up patching in the wrong order — not because CVSS is wrong, but because it's answering a question you didn't ask.

This is a comparison of what each signal actually measures, where they agree, where they contradict each other, and how to combine them into something you can actually run a remediation queue on.

What CVSS measures

CVSS (Common Vulnerability Scoring System) scores the technical severity of a vulnerability if it were exploited. It's a formula built from exploitability metrics (attack vector, complexity, privileges required, user interaction) and impact metrics (confidentiality, integrity, availability). The output is a number from 0.0 to 10.0, assigned once at publication by NVD or the vendor, and it rarely changes afterward.

CVSS answers: if someone exploits this, how bad is it?

It does not answer: is anyone exploiting this? Those are different questions, and conflating them is the single most common vulnerability-management mistake.

What EPSS measures

EPSS (Exploit Prediction Scoring System, maintained by FIRST.org) estimates the probability that a CVE will be exploited in the wild in the next 30 days. It's a machine-learning model trained on real exploitation telemetry, public exploit code availability, CVE metadata, and observed scanning/attack activity across the internet. The output is a continuous score from 0.0 to 1.0, updated daily.

EPSS answers: how likely is exploitation to happen soon?

Unlike CVSS, EPSS is not fixed at publication — it moves as real-world conditions change. A CVE published quietly in January can jump from EPSS 0.01 to EPSS 0.90 in March if a working exploit gets published or a botnet starts scanning for it.

What CISA KEV represents

CISA KEV (Known Exploited Vulnerabilities catalog) is not a score at all — it's a list. CISA adds a CVE to KEV only when there is confirmed evidence of active exploitation, not prediction, not theoretical risk. US federal agencies are required to remediate KEV entries within CISA-mandated deadlines (typically 2–3 weeks), which is a reasonable proxy for "this is currently being used to break into real organizations."

KEV answers: is this being exploited right now, confirmed?

It's binary — a CVE is either on the list or it isn't — and it's the strongest signal of the three because it requires actual observed exploitation, not a model's estimate of likelihood.

Why these three signals answer different questions

SignalQuestion answeredTypeUpdate frequencySet at
CVSSHow bad if exploited?0.0–10.0 scoreRarely, if everPublication
EPSSHow likely to be exploited soon?0.0–1.0 probabilityDailyContinuously
CISA KEVIs this confirmed exploited now?Yes/NoAs exploitation is observedContinuously

A vulnerability can score high on one axis and low on another. That's not a bug in any of the three systems — it's the point. CVSS is about the vulnerability itself. EPSS and KEV are about what attackers are actually doing with it.

CVSS vs EPSS

These diverge constantly. CVSS is assigned once and stays fixed; EPSS moves daily as threat intelligence accumulates. A CVE can carry a CVSS 9.8 and an EPSS of 0.003 — technically catastrophic, practically ignored by attackers, likely because it requires local access, a niche configuration, or exploitation is simply harder in practice than the CVSS formula suggests. The reverse also happens: a CVSS 6.5 vulnerability with a trivial, widely automated exploit can carry an EPSS above 0.80.

If you sort a Nessus export purely by CVSS, you will routinely put a 9.8-with-0.003-EPSS finding ahead of a 6.5-with-0.80-EPSS finding. That ordering is backwards from what attackers are actually doing.

CVSS vs KEV

KEV is the sharper, later-arriving signal. A vulnerability can sit at CVSS 9.8 for months with no KEV entry — meaning it's theoretically severe but nobody has been caught exploiting it yet — and then get added to KEV the day a ransomware crew starts using it as an initial-access vector. When that happens, the CVSS score doesn't change, but the correct remediation priority changes overnight. CVSS tells you what's structurally dangerous; KEV tells you what's currently on fire.

EPSS vs KEV

These are the closest of the three, but they're not redundant. EPSS is a prediction; KEV is a confirmation. High EPSS without a KEV entry means "our model thinks this is likely to get exploited soon" — useful, but probabilistic. KEV membership means "this has already happened, confirmed." In practice, most KEV entries also carry high EPSS scores, but not all high-EPSS CVEs make it into KEV — EPSS can flag CVEs before confirmed exploitation is observed and reported, which is exactly the early-warning use case KEV can't provide by design (it only lists what's already confirmed).

How the three combine

None of the three signals alone is a complete prioritization model. Used together, a reasonable composite looks like this:

  • KEV membership is a hard floor. If a CVE is confirmed exploited, it goes to the top of the queue regardless of what CVSS or EPSS say. There's no legitimate reason to argue with confirmed, active exploitation.
  • EPSS drives ranking among everything else. For findings not yet in KEV, EPSS is the best available forward-looking signal for "how urgent is this actually going to become."
  • CVSS provides a smaller, supporting weight. It still matters — a low-severity finding with a freak high EPSS reading is less concerning than a genuinely catastrophic one — but it shouldn't dominate the ranking the way it does when used alone.

VulnPilot's scoring engine implements exactly this structure: (KEV × 40) + (EPSS × 35) + (CVSS × 15) + (severity × 10), with any KEV match forced to a minimum score of 75 regardless of the other three terms. The weighting reflects the order of trust above — confirmed exploitation outweighs predicted exploitation, which outweighs theoretical severity.

A worked example: two real KEV entries, two very different CVSS scores

CVE-2021-44228 (Log4Shell) — CVSS 10.0, EPSS ~0.97, in KEV. Every signal agrees: fix immediately.

CVE-2023-34362 (MOVEit Transfer SQL injection, exploited by the Cl0p ransomware campaign) — CVSS 9.8, added to KEV within days of confirmed mass exploitation, EPSS spiking sharply once exploitation was observed. Again, every signal converges once exploitation starts — but notice that before the campaign began, this CVE looked like just another high-CVSS finding among hundreds. The KEV entry and the EPSS spike are what separated it from the noise, not the CVSS score, which was high from day one and told you nothing about timing.

Now the contrast case: a hypothetical CVSS 9.1 deserialization bug in an internal admin tool, published quietly, no public exploit code, EPSS sitting at 0.02, not in KEV. By CVSS alone this looks nearly as urgent as MOVEit. By EPSS and KEV, it's a background-priority fix — patch it in the next normal cycle, not tonight.

If your process sorts by CVSS alone, that admin-tool bug and MOVEit look almost identical. They are not.

How this relates to real Nessus findings

A mid-size Nessus scan routinely returns 200–800 findings, a large fraction of them CVSS Critical or High. Nessus reports the vulnerability's technical severity — it does not (and isn't designed to) tell you which of those hundreds are actually being exploited against organizations like yours right now. That gap is exactly what EPSS and KEV close. Enriching a raw Nessus export with EPSS scores and KEV status turns "600 findings, most of them red" into a short, defensible list of what actually needs attention this week versus what can wait for the next patch cycle.

A practical prioritization workflow

  1. Export your scan. Nessus, or any scanner that reports CVE identifiers alongside CVSS.
  2. Enrich every finding with current EPSS and KEV status. Both are free, public datasets — EPSS from FIRST.org, KEV from CISA — but they need to be pulled and joined against your findings, ideally on a recurring schedule since EPSS moves daily.
  3. Sort by a composite score, not raw CVSS. Anything in KEV goes to the top, full stop. Everything else ranks primarily by EPSS, with CVSS as a secondary factor.
  4. Set remediation SLAs by tier, not by CVSS bucket alone. "All Criticals in 30 days" ignores that some Criticals are inert and some Mediums are actively exploited. Tie SLA to the composite priority, not the raw CVSS severity label.
  5. Re-run the enrichment regularly. A finding that was low-EPSS last month can spike this month. Static, one-time prioritization goes stale.

How VulnPilot uses these signals

VulnPilot is a CLI that runs exactly this workflow against a Nessus CSV export. vulnpilot update-feeds pulls the current CISA KEV catalog and FIRST EPSS dataset locally. vulnpilot analyze export.csv joins your findings against both feeds, applies the composite scoring formula above, and outputs a ranked list — including a ★KEV flag on any finding with confirmed active exploitation and a CRITICAL NOW priority label for anything that crosses the KEV floor or a high composite score. Nothing leaves your machine; the feeds are cached locally and the analysis runs offline once they're downloaded.

It doesn't invent a new scoring methodology — it operationalizes the same CVSS/EPSS/KEV combination described above so you don't have to build the enrichment pipeline yourself.

For the individual signals in more depth, see what CISA KEV means for remediation priority and what an EPSS score actually represents. For the original argument on why CVSS alone produces bad prioritization ordering, with a worked composite-score example, see Why CVSS Alone Is Not Enough.