| name | implementing-epss-score-for-vulnerability-prioritization |
| description | Integrate FIRST's Exploit Prediction Scoring System (EPSS) API to prioritize vulnerability remediation based on real-world exploitation probability within 30 days. |
| domain | cybersecurity |
| subdomain | vulnerability-management |
| tags | ["epss","vulnerability-prioritization","first","exploit-prediction","cvss","risk-based","machine-learning"] |
| version | 1.0 |
| author | mahipal |
| license | Apache-2.0 |
Implementing EPSS Score for Vulnerability Prioritization
Overview
The Exploit Prediction Scoring System (EPSS) is a data-driven model developed by FIRST (Forum of Incident Response and Security Teams) that estimates the probability of a CVE being exploited in the wild within the next 30 days. EPSS produces scores from 0.0 to 1.0 (0% to 100%) using machine learning trained on real-world exploitation data. Unlike CVSS which measures severity, EPSS measures likelihood of exploitation, making it essential for risk-based vulnerability prioritization.
Prerequisites
- Python 3.9+ with
requests, pandas, matplotlib
- Access to FIRST EPSS API (https://api.first.org/data/v1/epss)
- Vulnerability scan results with CVE identifiers
- Optional: NVD API key for CVSS enrichment
EPSS API Usage
Query Single CVE
curl -s "https://api.first.org/data/v1/epss?cve=CVE-2024-3400" | python3 -m json.tool
Query Multiple CVEs
curl -s "https://api.first.org/data/v1/epss?cve=CVE-2024-3400,CVE-2024-21887,CVE-2023-44228" | \
python3 -c "
import sys, json
data = json.load(sys.stdin)
for item in data['data']:
pct = float(item['epss']) * 100
print(f\"{item['cve']}: {pct:.2f}% exploitation probability (percentile: {item['percentile']})\")
"
Download Full EPSS Dataset
curl -s "https://epss.cyentia.com/epss_scores-current.csv.gz" | gunzip > epss_scores_current.csv
wc -l epss_scores_current.csv
head -5 epss_scores_current.csv
Query Historical EPSS Scores
curl -s "https://api.first.org/data/v1/epss?cve=CVE-2024-3400&date=2024-04-12"
curl -s "https://api.first.org/data/v1/epss?cve=CVE-2024-3400&scope=time-series"
Prioritization Strategy
EPSS + CVSS Combined Approach
| EPSS Score | CVSS Score | Priority | Action |
|---|
| > 0.7 | >= 9.0 | P0 - Immediate | Remediate within 24 hours |
| > 0.7 | >= 7.0 | P1 - Urgent | Remediate within 48 hours |
| > 0.4 | >= 7.0 | P2 - High | Remediate within 7 days |
| > 0.1 | >= 4.0 | P3 - Medium | Remediate within 30 days |
| <= 0.1 | >= 7.0 | P3 - Medium | Remediate within 30 days |
| <= 0.1 | < 7.0 | P4 - Low | Remediate within 90 days |
EPSS Percentile Thresholds
- Top 1% (percentile >= 0.99): Extremely likely to be exploited; treat as Critical
- Top 5% (percentile >= 0.95): High exploitation probability; prioritize remediation
- Top 10% (percentile >= 0.90): Elevated risk; schedule for near-term remediation
- Bottom 50%: Low exploitation probability; handle in normal patch cycle
Implementation
import requests
import pandas as pd
from datetime import datetime
def fetch_epss_scores(cve_list):
"""Fetch EPSS scores for a list of CVEs from FIRST API."""
scores = {}
batch_size = 100
for i in range(0, len(cve_list), batch_size):
batch = cve_list[i:i + batch_size]
resp = requests.get(
"https://api.first.org/data/v1/epss",
params={"cve": ",".join(batch)},
timeout=30
)
if resp.status_code == 200:
for entry in resp.json().get("data", []):
scores[entry["cve"]] = {
"epss": float(entry["epss"]),
"percentile": float(entry["percentile"]),
"date": entry.get("date", ""),
}
return scores
def prioritize_vulnerabilities(scan_results_csv, output_csv):
"""Enrich scan results with EPSS scores and assign priorities."""
df = pd.read_csv(scan_results_csv)
cve_list = df["cve_id"].dropna().unique().tolist()
epss_data = fetch_epss_scores(cve_list)
df["epss_score"] = df["cve_id"].map( c: epss_data.get(c, {}).get(, ))
df[] = df[].( c: epss_data.get(c, {}).get(, ))
():
epss = row.get(, )
cvss = row.get(, )
epss > cvss >= :
epss > cvss >= :
epss > cvss >= :
epss > cvss >= :
df[] = df.apply(assign_priority, axis=)
df = df.sort_values([, ], ascending=[, ])
df.to_csv(output_csv, index=)
()
()
()
()
()
()
df
EPSS Trend Analysis
def fetch_epss_timeseries(cve_id):
"""Get historical EPSS scores for trend analysis."""
resp = requests.get(
"https://api.first.org/data/v1/epss",
params={"cve": cve_id, "scope": "time-series"},
timeout=30
)
if resp.status_code == 200:
return resp.json().get("data", [])
return []
def detect_epss_spikes(cve_id, threshold=0.3):
"""Detect significant EPSS score increases indicating emerging threats."""
timeseries = fetch_epss_timeseries(cve_id)
if len(timeseries) < 2:
return False
sorted_data = sorted(timeseries, key=lambda x: x.get("date", ""))
latest = float(sorted_data[-1].get("epss", 0))
previous = float(sorted_data[-2].get("epss", 0))
increase = latest - previous
if increase >= threshold:
print(f"[!] EPSS spike detected for {cve_id}: {previous:.3f} -> {latest:.3f} (+{increase:.3f})")
return True
References