PRACTITIONER GUIDE | VULNERABILITY MANAGEMENT
Practitioner GuideUpdated 11 min read

EPSS vs CVSS: How to Use Exploit Prediction Scores to Prioritize Patching When You Cannot Patch Everything

~7% of CVEs
are ever exploited in the wild, according to FIRST.org research. CVSS-only prioritization treats the other 93% as equally urgent, creating a patching backlog that buries the CVEs actually being exploited in noise
EPSS v4
released March 2025, ingests more than 250,000 threat intelligence data points daily and scores CVEs within 24 hours of NVD publication. It also scores CVEs in the NVD backlog that previously had no EPSS score
0.0 to 1.0
is the EPSS score range, representing the probability of exploitation within 30 days. A score of 0.95 means 95% probability. Most CVEs score below 0.01 -- the high-EPSS population is a small fraction of total CVEs
CVSS alone misses 28%
of exploited CVEs in Q1 2025 carried only Medium base CVSS scores. Filtering by CVSS 7+ or 9+ alone misses a significant portion of actively exploited vulnerabilities that have been scored conservatively

SponsoredRetool

Retool's new app builder is where AI-generated code ships safely

Building apps with AI is easy. Getting them to production safely is another story.

Start building for free today

Every vulnerability management program faces the same problem: more CVEs than patch capacity. CVSS scores sort by potential severity but ignore exploitation probability -- a CVSS 9.8 with zero exploitation activity is less urgent than a CVSS 6.5 that is actively being exploited in ransomware campaigns. EPSS is the model that fills this gap. Used alongside CVSS and the CISA KEV catalog, it reduces a list of thousands of critical CVEs to a workable priority queue of CVEs that are both severe and likely to be used against you.

How EPSS Works and What the Score Means

EPSS is a machine learning model trained on CVE characteristics and observed exploitation data from multiple threat intelligence sources including exploit databases, malware repositories, and honeypot networks. It outputs a probability score between 0 and 1 representing the likelihood that a CVE will be observed in exploitation activity within the next 30 days.

Key properties:

  • Score updates daily: EPSS scores change as new exploitation activity is observed. A CVE that had a score of 0.02 last month may be 0.87 this week because a PoC was published.
  • Score is not permanent: High EPSS scores often decay after the initial exploitation wave. Monitor score changes, not just current scores.
  • Percentile is often more useful than raw score: EPSS provides both a score and a percentile. A score of 0.05 sounds low but if it represents the 94th percentile of all CVEs, it means 94% of all CVEs are less likely to be exploited.

The EPSS API:

import requests
# Get EPSS score for a specific CVE
cve_id = 'CVE-2024-21762'
response = requests.get(f'https://api.first.org/data/v1/epss?cve={cve_id}')
data = response.json()
print(data['data'][0])  # {'cve': 'CVE-2024-21762', 'epss': '0.96813', 'percentile': '0.99988', 'date': '2026-06-12'}
# Bulk fetch for a list of CVEs
curl 'https://api.first.org/data/v1/epss?cve=CVE-2024-21762,CVE-2024-30078,CVE-2023-44487'

Building a Composite Priority Score: EPSS + CVSS + KEV

Neither EPSS nor CVSS alone is sufficient. The composite approach:

Tier 1 (patch within 24 hours):

  • CVE is in the CISA KEV catalog (confirmed active exploitation)
  • Regardless of CVSS or EPSS score -- KEV means it is being exploited right now

Tier 2 (patch within 7 days):

  • EPSS score above 0.5 (50% probability of exploitation in 30 days) AND
  • CVSS score above 7.0 (High or Critical)
  • This is the population of CVEs that are both severe and likely to be weaponized

Tier 3 (patch within 30 days per normal cycle):

  • CVSS 9.0+ OR EPSS above 0.3, not in Tier 1 or 2

Tier 4 (patch in next scheduled maintenance):

  • Everything else above CVSS 4.0

Practical implementation in Python:

import requests

def get_epss_score(cve_id):
    r = requests.get(f'https://api.first.org/data/v1/epss?cve={cve_id}')
    data = r.json().get('data', [])
    return float(data[0]['epss']) if data else 0.0

def prioritize_cve(cve_id, cvss_score, in_kev=False):
    epss = get_epss_score(cve_id)
    if in_kev:
        return 1, 'Tier 1 - Patch in 24h (KEV confirmed)'
    if epss >= 0.5 and cvss_score >= 7.0:
        return 2, f'Tier 2 - Patch in 7 days (EPSS={epss:.2f}, CVSS={cvss_score})'
    if cvss_score >= 9.0 or epss >= 0.3:
        return 3, f'Tier 3 - Patch in 30 days (EPSS={epss:.2f}, CVSS={cvss_score})'
    return 4, f'Tier 4 - Normal cycle (EPSS={epss:.2f}, CVSS={cvss_score})'
Free daily briefing

Briefings like this, every morning before 9am.

Threat intel, active CVEs, and campaign alerts, distilled for practitioners. 50,000+ subscribers. No noise.

Integrating EPSS into Your Existing Vulnerability Scanner Output

Most vulnerability scanners (Tenable, Qualys, Rapid7) export CVE lists in CSV or JSON. Enrich the scanner output with EPSS scores before generating your patch priority list.

Bulk EPSS enrichment script (Python):

import requests
import csv
import time

def enrich_cve_list(input_csv, output_csv):
    with open(input_csv) as f:
        rows = list(csv.DictReader(f))
    
    cve_ids = [row['CVE'] for row in rows if row.get('CVE')]
    
    # EPSS API supports up to 1000 CVEs per request
    epss_data = {}
    for i in range(0, len(cve_ids), 100):
        batch = cve_ids[i:i+100]
        cve_param = ','.join(batch)
        r = requests.get(f'https://api.first.org/data/v1/epss?cve={cve_param}')
        for item in r.json().get('data', []):
            epss_data[item['cve']] = (item['epss'], item['percentile'])
        time.sleep(0.5)  # Respect rate limits
    
    # Write enriched output
    with open(output_csv, 'w', newline='') as f:
        fieldnames = rows[0].keys() | {'EPSS_Score', 'EPSS_Percentile'}
        writer = csv.DictWriter(f, fieldnames=fieldnames)
        writer.writeheader()
        for row in rows:
            cve = row.get('CVE', '')
            epss, pct = epss_data.get(cve, ('0', '0'))
            row['EPSS_Score'] = epss
            row['EPSS_Percentile'] = pct
            writer.writerow(row)

enrich_cve_list('scanner_output.csv', 'enriched_vulns.csv')

After enrichment, sort by EPSS_Score descending within each CVSS severity band to get your priority queue.

Monitoring EPSS Score Changes for Trending CVEs

A CVE that jumps from EPSS 0.02 to 0.85 in 48 hours indicates active weaponization -- a PoC was published, a campaign started, or it entered a widely-used exploit kit. Monitoring score changes is as important as monitoring current scores.

Daily delta monitoring:

import requests
from datetime import date, timedelta

def get_epss_on_date(cve_id, date_str):
    r = requests.get(f'https://api.first.org/data/v1/epss?cve={cve_id}&date={date_str}')
    data = r.json().get('data', [])
    return float(data[0]['epss']) if data else 0.0

def check_score_increase(cve_id, threshold=0.3):
    today = str(date.today())
    yesterday = str(date.today() - timedelta(days=1))
    current = get_epss_on_date(cve_id, today)
    previous = get_epss_on_date(cve_id, yesterday)
    delta = current - previous
    if delta >= threshold:
        print(f'ALERT: {cve_id} EPSS increased by {delta:.3f} (now {current:.3f})')
    return delta

Practical alert threshold: A CVE jumping 0.3 or more in a single day warrants immediate review. If that CVE affects systems in your environment and the new score exceeds 0.5, escalate to Tier 1 or Tier 2 treatment regardless of when it was originally scheduled for patching.

The bottom line

EPSS changes patch prioritization from 'sort by CVSS score and work down the list' to 'patch the things that are actually being exploited.' The composite workflow: KEV catalog for confirmed exploitation (patch in 24 hours), EPSS above 0.5 plus CVSS above 7.0 for likely imminent exploitation (patch in 7 days), and normal cycles for everything else. The EPSS API is free, returns results in under a second, and can be integrated into any scanner CSV export with 20 lines of Python. Monitor daily score changes for sudden spikes that indicate newly weaponized CVEs.

Frequently asked questions

What EPSS score threshold should I use for emergency patching?

FIRST.org does not publish a single threshold recommendation because the right threshold depends on your patch capacity and risk tolerance. Common operational thresholds: 0.5 (high confidence -- 50%+ probability in 30 days) for escalating to a 7-day patch SLA, and 0.3 (moderate probability) for escalating within the current patch cycle. For organizations that are currently only patching CVSS 9+, adding an EPSS filter of 0.5+ to CVSS 7+ is a practical starting point that typically reduces the list by 60-80% while covering the high-exploitation-probability population.

Why does EPSS sometimes give a low score to CVEs that are being actively exploited?

EPSS is a probability model trained on observed exploitation signals. It can lag behind very new exploitation waves -- if a CVE just entered active exploitation but that signal has not propagated through the threat intelligence feeds EPSS ingests, the score may be low for a day or two. This is why the CISA KEV catalog is a separate first-tier signal -- it represents confirmed exploitation that a human at CISA has verified, without the model lag. Use EPSS and KEV together; do not rely on EPSS alone to catch zero-day or very-recently-weaponized CVEs.

Is EPSS available for CVEs that CVSS has not scored yet?

Yes, as of EPSS v4 (March 2025). EPSS v4 scores CVEs in the NVD backlog that do not yet have an official CVSS score. This addresses one of the practical gaps in earlier versions -- organizations could not get EPSS scores for new CVEs that were in the NVD analysis queue. Check the EPSS API for the CVE ID directly; if it returns a score, the model has sufficient data to estimate exploitation probability regardless of NVD scoring status.

Can I use EPSS to justify not patching low-CVSS vulnerabilities?

EPSS is a tool for prioritizing when to patch, not whether to patch. A CVE with EPSS 0.001 (very unlikely to be exploited) and CVSS 4.0 is still a vulnerability in your environment that should be remediated -- just not at the expense of the EPSS 0.9, CVSS 7.5 CVE waiting in the queue. Using EPSS to indefinitely defer low-probability CVEs creates technical debt. The defensible use is: EPSS high + CVSS high = patch immediately, EPSS low + CVSS low = patch in normal cycle, never = never patch.

How do I integrate EPSS scores into an existing vulnerability management tool?

The EPSS API at api.first.org/epss provides a JSON endpoint that returns current and historical EPSS scores for any CVE ID. Most vulnerability management platforms (Tenable, Rapid7, Qualys) have begun incorporating EPSS natively in their scoring displays, but for platforms that do not, you can supplement via API integration: fetch EPSS scores for all CVEs in your open findings using the bulk endpoint (accepts comma-separated CVE IDs up to 100 per request), store the EPSS score alongside the existing CVSS score, and sort findings by a composite score formula such as `(CVSS/10 * 0.4) + (EPSS * 0.6)`. Refresh EPSS scores weekly since they update as new exploitation signals emerge.

What is the CISA Known Exploited Vulnerabilities catalog and how should I use it in my patching workflow?

The CISA KEV catalog (cisa.gov/known-exploited-vulnerabilities-catalog) is a maintained list of vulnerabilities that CISA has confirmed are actively exploited in the wild. Federal agencies are required to remediate KEV entries within 2 weeks (for Critical) or 3 weeks (for other severities) under Binding Operational Directive 22-01. For non-federal organizations, the KEV serves as a high-confidence signal for prioritization: a vulnerability on the KEV list has confirmed active exploitation, removing the uncertainty that makes CVSS and EPSS probabilistic. Integrate the KEV into your vulnerability management workflow by: downloading the KEV JSON feed (cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json) and cross-referencing it against your open findings daily, creating a separate SLA for KEV findings that is shorter than your standard critical finding SLA (24-72 hours for KEV entries versus 7-14 days for non-KEV critical), and flagging KEV status in your vulnerability dashboard separately from CVSS and EPSS scores. A finding that is KEV-listed at any CVSS score should be treated as higher priority than a non-KEV CVSS 10.

Sources & references

  1. FIRST.org: EPSS Model and User Guide
  2. FIRST.org: EPSS API documentation
  3. CISA: Known Exploited Vulnerabilities Catalog

Free resources

25
Free download

Critical CVE Reference Card 2025–2026

25 actively exploited vulnerabilities with CVSS scores, exploit status, and patch availability. Print it, pin it, share it with your SOC team.

No spam. Unsubscribe anytime.

Free download

Ransomware Incident Response Playbook

Step-by-step 24-hour IR checklist covering detection, containment, eradication, and recovery. Built for SOC teams, IR leads, and CISOs.

No spam. Unsubscribe anytime.

Free newsletter

Get threat intel before your inbox does.

50,000+ security professionals read Decryption Digest for early warnings on zero-days, ransomware, and nation-state campaigns. Free, daily, no spam.

Unsubscribe anytime. We never sell your data.

Eric Bang
Author

Founder & Cybersecurity Evangelist, Decryption Digest

Cybersecurity professional with expertise in threat intelligence, vulnerability research, and enterprise security. Covers zero-days, ransomware, and nation-state operations for 50,000+ security professionals every morning.

Black Hat Giveaway

Win a $2,495 Black Hat pass.

Full-access to Black Hat USA 2026 in Las Vegas. Subscribe free to enter.

Joins Decryption Digest daily briefing. Unsubscribe anytime.

Giveaway: Black Hat USA 2026 Full-Access Pass ($2,495 value)

Details →
Daily Briefing

Subscribe to enter the giveaway

Every subscriber is automatically entered. You also get daily threat intel every morning: zero-days, ransomware, and nation-state campaigns. Free. No spam.

Already subscribed? You're already entered.

Giveaway

Win a $2,495 Black Hat USA 2026 pass.