EPSS vs CVSS: Which Vulnerability Score Actually Matters?
If you've ever run a dependency scan, you've seen CVSS scores: numbers from 0 to 10 telling you how severe a vulnerability is. A 9.8 is critical. A 3.1 is low. Simple enough.
The problem is that CVSS doesn't tell you the one thing you actually need to know: is anyone exploiting this?
That's what EPSS answers. And understanding the difference between these two scoring systems changes how you prioritize security work.
What CVSS measures
The Common Vulnerability Scoring System (CVSS) rates a vulnerability's potential impact. It considers factors like:
- Attack vector (network, adjacent, local, physical)
- Attack complexity (low or high)
- Privileges required
- User interaction needed
- Impact on confidentiality, integrity, and availability
A CVSS score answers: "If this vulnerability were exploited, how bad would it be?"
It does not answer: "How likely is exploitation?" A vulnerability that requires physical access to a machine and a specific kernel version might get a CVSS of 7.0 (high) even though no one has ever exploited it in the wild. Meanwhile, a vulnerability with a CVSS of 5.3 (medium) might be in every automated exploit kit on the internet.
What EPSS measures
The Exploit Prediction Scoring System (EPSS) is a machine learning model maintained by FIRST.org that estimates the probability a vulnerability will be exploited in the wild within the next 30 days.
EPSS outputs a score between 0 and 1 (often shown as a percentage). An EPSS of 0.87 means there's an 87% chance this vulnerability will see active exploitation within a month. An EPSS of 0.001 means it almost certainly won't.
The model is trained on real-world exploitation data: honeypot hits, IDS signatures, public exploit code, threat intelligence feeds, and vulnerability metadata. It updates daily.
EPSS answers: "Is this vulnerability actually being used to attack systems right now?"
The prioritization problem
Consider a typical Node.js project with 800+ transitive dependencies. A vulnerability scan finds 12 CVEs. Sorting by CVSS:
| CVE | Package | CVSS | Severity |
|---|---|---|---|
| CVE-2024-21538 | cross-spawn | 7.5 | High |
| CVE-2024-37890 | ws | 7.5 | High |
| CVE-2024-43788 | webpack | 6.1 | Medium |
| CVE-2024-47764 | cookie | 5.3 | Medium |
CVSS says cross-spawn and ws are equally urgent. Both are 7.5/High. A team triaging by CVSS would treat them the same.
Now add EPSS:
| CVE | Package | CVSS | EPSS | Real priority |
|---|---|---|---|---|
| CVE-2024-21538 | cross-spawn | 7.5 | 0.87 | Fix now |
| CVE-2024-47764 | cookie | 5.3 | 0.42 | Fix soon |
| CVE-2024-37890 | ws | 7.5 | 0.03 | Schedule it |
| CVE-2024-43788 | webpack | 6.1 | 0.01 | Backlog |
EPSS reorders the list entirely. The cross-spawn vulnerability (command injection, exploit code widely available) is the clear emergency. The cookie issue ranks second despite its lower CVSS — it's actually being exploited. The ws DoS vulnerability, despite matching cross-spawn's CVSS score, is almost never exploited in practice.
This is the core insight: CVSS measures theoretical severity. EPSS measures real-world risk.
Why CVSS alone is misleading
Research from FIRST.org shows that only about 2–5% of published CVEs are ever exploited in the wild. Yet CVSS labels roughly 60% of all CVEs as "high" or "critical" (score ≥ 7.0).
When everything is critical, nothing is. Teams that triage by CVSS alone face two failure modes:
- Alert fatigue. 60% of your scan results are "high" or "critical." You can't fix them all this sprint. So you fix the top few, batch the rest, and hope nothing slips through. Some of those batched items are actually being exploited.
- Misallocation. Your team spends a day upgrading a library with a CVSS 9.8 vulnerability that has never been exploited (EPSS 0.001), while a CVSS 5.3 vulnerability with EPSS 0.70 sits in the backlog because it's "medium severity."
How EPSS is calculated
EPSS v3 uses a gradient-boosted model trained on:
- Exploit code availability — is there a public proof-of-concept? A Metasploit module?
- Exploit maturity — has the exploit been weaponized?
- Vulnerability age — newer CVEs with exploit code trend upward
- CVSS components — attack vector, complexity, etc. (yes, CVSS feeds into EPSS)
- Threat intelligence signals — IDS/IPS signatures, dark web mentions, honeypot data
- Vendor and product — some software ecosystems see more exploitation attempts
The model retrains daily. Yesterday's EPSS of 0.02 can jump to 0.85 overnight when a working exploit hits GitHub.
Using both scores together
CVSS and EPSS aren't competing — they answer different questions. The most effective prioritization uses both:
| High EPSS (>0.1) | Low EPSS (<0.1) | |
|---|---|---|
| High CVSS (≥7.0) | Fix immediately. High impact, actively exploited. | Schedule for next sprint. Severe but not in active use. |
| Low CVSS (<7.0) | Fix soon. Lower impact, but attackers are trying. | Backlog. Low impact, low likelihood. |
The high-CVSS, low-EPSS quadrant is where most wasted effort lives. These are the "critical" vulnerabilities that exist in theory but never get exploited. They're worth fixing, but not at the expense of the medium-CVSS, high-EPSS issues that are actually hitting production systems.
Applying this to your dependency scans
Most vulnerability scanners report CVSS and stop there. A few now include EPSS, but present it as a secondary detail.
VulnFeed sorts by EPSS by default. When you scan a project, the most likely-to-be-exploited vulnerabilities appear first — regardless of their CVSS score. You get both numbers, but the ordering reflects real-world risk rather than theoretical severity.
Found 4 vulnerabilities in 847 packages: 1. CVE-2024-21538 (cross-spawn) — CVSS 7.5, EPSS 0.87 Affected: <7.0.5 | Fix: 7.0.5 Command injection via args on Windows 2. CVE-2024-47764 (cookie) — CVSS 5.3, EPSS 0.42 Affected: <0.7.0 | Fix: 0.7.0 Cookie header parsing allows prototype pollution 3. CVE-2024-37890 (ws) — CVSS 7.5, EPSS 0.03 Affected: <8.17.1 | Fix: 8.17.1 Denial of service via large WebSocket frame 4. CVE-2024-43788 (webpack) — CVSS 6.1, EPSS 0.01 Affected: 5.0.0–5.94.0 | Fix: 5.94.0 XSS in development server error overlay
The engineer sees the real priority order immediately. No mental filtering. No spreadsheet resorting.
The bottom line
CVSS tells you what could happen. EPSS tells you what is happening. Both are useful. But if you're triaging a backlog of 50 CVEs and can only fix 5 this week, sort by EPSS.