mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-20 14:30:59 +03:00
Initial commit - 611 cybersecurity skills across all subdomains
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
---
|
||||
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: MIT
|
||||
---
|
||||
|
||||
# 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
|
||||
```bash
|
||||
# Get EPSS score for a specific CVE
|
||||
curl -s "https://api.first.org/data/v1/epss?cve=CVE-2024-3400" | python3 -m json.tool
|
||||
|
||||
# Response:
|
||||
# {
|
||||
# "status": "OK",
|
||||
# "status-code": 200,
|
||||
# "version": "1.0",
|
||||
# "total": 1,
|
||||
# "data": [
|
||||
# {
|
||||
# "cve": "CVE-2024-3400",
|
||||
# "epss": "0.95732",
|
||||
# "percentile": "0.99721",
|
||||
# "date": "2024-04-15"
|
||||
# }
|
||||
# ]
|
||||
# }
|
||||
```
|
||||
|
||||
### Query Multiple CVEs
|
||||
```bash
|
||||
# Batch query up to 100 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
|
||||
```bash
|
||||
# Download complete daily EPSS scores (CSV format)
|
||||
curl -s "https://epss.cyentia.com/epss_scores-current.csv.gz" | gunzip > epss_scores_current.csv
|
||||
|
||||
# Check size and preview
|
||||
wc -l epss_scores_current.csv
|
||||
head -5 epss_scores_current.csv
|
||||
```
|
||||
|
||||
### Query Historical EPSS Scores
|
||||
```bash
|
||||
# Get EPSS score for a specific date
|
||||
curl -s "https://api.first.org/data/v1/epss?cve=CVE-2024-3400&date=2024-04-12"
|
||||
|
||||
# Get time series data
|
||||
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
|
||||
|
||||
```python
|
||||
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(lambda c: epss_data.get(c, {}).get("epss", 0))
|
||||
df["epss_percentile"] = df["cve_id"].map(lambda c: epss_data.get(c, {}).get("percentile", 0))
|
||||
|
||||
def assign_priority(row):
|
||||
epss = row.get("epss_score", 0)
|
||||
cvss = row.get("cvss_score", 0)
|
||||
if epss > 0.7 and cvss >= 9.0:
|
||||
return "P0"
|
||||
if epss > 0.7 and cvss >= 7.0:
|
||||
return "P1"
|
||||
if epss > 0.4 and cvss >= 7.0:
|
||||
return "P2"
|
||||
if epss > 0.1 or cvss >= 7.0:
|
||||
return "P3"
|
||||
return "P4"
|
||||
|
||||
df["priority"] = df.apply(assign_priority, axis=1)
|
||||
df = df.sort_values(["priority", "epss_score"], ascending=[True, False])
|
||||
df.to_csv(output_csv, index=False)
|
||||
print(f"[+] Prioritized {len(df)} vulnerabilities -> {output_csv}")
|
||||
print(f" P0: {len(df[df['priority']=='P0'])}")
|
||||
print(f" P1: {len(df[df['priority']=='P1'])}")
|
||||
print(f" P2: {len(df[df['priority']=='P2'])}")
|
||||
print(f" P3: {len(df[df['priority']=='P3'])}")
|
||||
print(f" P4: {len(df[df['priority']=='P4'])}")
|
||||
return df
|
||||
```
|
||||
|
||||
## EPSS Trend Analysis
|
||||
|
||||
```python
|
||||
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
|
||||
return False
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [FIRST EPSS Official](https://www.first.org/epss/)
|
||||
- [EPSS API Documentation](https://www.first.org/epss/api)
|
||||
- [EPSS Model Documentation](https://www.first.org/epss/model)
|
||||
- [EPSS Data Downloads](https://epss.cyentia.com/)
|
||||
- [Cyentia Institute Research](https://www.cyentia.com/epss/)
|
||||
@@ -0,0 +1,41 @@
|
||||
# EPSS Vulnerability Prioritization Policy Template
|
||||
|
||||
## Priority Matrix
|
||||
|
||||
| Priority | EPSS Threshold | CVSS Range | KEV Status | Remediation SLA |
|
||||
|----------|---------------|-----------|------------|-----------------|
|
||||
| P0 - Immediate | > 0.70 | >= 9.0 | Any | 24 hours |
|
||||
| P0 - Immediate | Any | Any | In KEV + Critical CVSS | 24 hours |
|
||||
| P1 - Urgent | > 0.70 | >= 7.0 | Any | 48 hours |
|
||||
| P1 - Urgent | Any | Any | In KEV | 48 hours |
|
||||
| P2 - High | > 0.40 | >= 7.0 | Not in KEV | 7 days |
|
||||
| P3 - Medium | > 0.10 | >= 4.0 | Not in KEV | 30 days |
|
||||
| P3 - Medium | <= 0.10 | >= 7.0 | Not in KEV | 30 days |
|
||||
| P4 - Low | <= 0.10 | < 7.0 | Not in KEV | 90 days |
|
||||
|
||||
## Daily EPSS Enrichment Schedule
|
||||
|
||||
```
|
||||
# crontab entry for daily EPSS enrichment
|
||||
0 6 * * * /opt/vuln-mgmt/scripts/process.py --input /data/open_vulns.csv --output /data/prioritized.csv --bulk
|
||||
```
|
||||
|
||||
## Input CSV Format
|
||||
|
||||
```csv
|
||||
cve_id,host,port,cvss_score,severity,description
|
||||
CVE-2024-3400,fw-01.corp.local,443,10.0,critical,PAN-OS command injection
|
||||
CVE-2024-21887,vpn-01.corp.local,443,9.1,critical,Ivanti Connect Secure auth bypass
|
||||
CVE-2023-44228,app-01.corp.local,8080,10.0,critical,Log4Shell RCE
|
||||
```
|
||||
|
||||
## EPSS Score Interpretation Guide
|
||||
|
||||
| EPSS Range | Interpretation | Recommended Action |
|
||||
|-----------|---------------|-------------------|
|
||||
| 0.90 - 1.00 | Near certainty of exploitation | Immediate patching or isolation |
|
||||
| 0.70 - 0.89 | Very high exploitation probability | Priority remediation queue |
|
||||
| 0.40 - 0.69 | Significant exploitation risk | Accelerated remediation |
|
||||
| 0.10 - 0.39 | Moderate exploitation probability | Standard remediation cycle |
|
||||
| 0.01 - 0.09 | Low exploitation probability | Normal patch cycle |
|
||||
| 0.00 - 0.009 | Negligible exploitation probability | Best-effort remediation |
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
# Standards and References - EPSS Vulnerability Prioritization
|
||||
|
||||
## Primary Standards
|
||||
|
||||
### FIRST EPSS
|
||||
- **Source**: Forum of Incident Response and Security Teams
|
||||
- **URL**: https://www.first.org/epss/
|
||||
- **API**: https://api.first.org/data/v1/epss
|
||||
- **Model**: Machine learning trained on real exploitation events, updated daily
|
||||
- **Versions**: v1 (2021), v2 (2022), v3 (2023), v4 (2025)
|
||||
|
||||
### CVSS v3.1 and v4.0
|
||||
- **Source**: FIRST
|
||||
- **URL**: https://www.first.org/cvss/
|
||||
- **Relevance**: EPSS complements CVSS; CVSS measures severity, EPSS measures exploitation probability
|
||||
|
||||
### CISA Stakeholder-Specific Vulnerability Categorization (SSVC)
|
||||
- **URL**: https://www.cisa.gov/stakeholder-specific-vulnerability-categorization-ssvc
|
||||
- **Relevance**: SSVC uses exploitation status as a key decision point; EPSS provides data-driven input
|
||||
|
||||
### CISA Known Exploited Vulnerabilities (KEV)
|
||||
- **URL**: https://www.cisa.gov/known-exploited-vulnerabilities-catalog
|
||||
- **Relevance**: KEV confirms active exploitation; EPSS predicts future exploitation probability
|
||||
|
||||
## Research Papers
|
||||
|
||||
### Original EPSS Paper
|
||||
- **Title**: "Improving Vulnerability Remediation Through Better Exploit Prediction"
|
||||
- **Authors**: Jay Jacobs, Sasha Romanosky, Benjamin Edwards, Michael Roytman, Idris Adjerid
|
||||
- **Published**: Workshop on the Economics of Information Security (WEIS), 2021
|
||||
|
||||
### EPSS v3 Model
|
||||
- **Features**: 1,477 features including CVE properties, vendor data, social media mentions, exploit code availability
|
||||
- **Training Data**: Historical exploitation events from multiple sources
|
||||
- **Performance**: AUC of 0.85+ for 30-day exploitation prediction
|
||||
|
||||
## Data Sources Used by EPSS
|
||||
|
||||
| Source | Data Type | Update Frequency |
|
||||
|--------|----------|-----------------|
|
||||
| NVD | CVE metadata, CVSS scores | Real-time |
|
||||
| CISA KEV | Confirmed exploitation | As new CVEs added |
|
||||
| Exploit-DB | Public exploit code | Daily |
|
||||
| GitHub | Exploit PoC repositories | Daily |
|
||||
| Metasploit | Exploit modules | Weekly |
|
||||
| SecurityFocus | Vulnerability discussions | Daily |
|
||||
| Social Media | Twitter/X mentions of CVEs | Real-time |
|
||||
| Fortinet | Exploitation telemetry | Daily |
|
||||
| AlienVault OTX | Threat intelligence | Daily |
|
||||
|
||||
## API Reference
|
||||
|
||||
### Endpoints
|
||||
- **Single CVE**: `GET https://api.first.org/data/v1/epss?cve=CVE-YYYY-NNNNN`
|
||||
- **Multiple CVEs**: `GET https://api.first.org/data/v1/epss?cve=CVE-1,CVE-2,...`
|
||||
- **Date-specific**: `GET https://api.first.org/data/v1/epss?cve=CVE-YYYY-NNNNN&date=YYYY-MM-DD`
|
||||
- **Time series**: `GET https://api.first.org/data/v1/epss?cve=CVE-YYYY-NNNNN&scope=time-series`
|
||||
- **Top scoring**: `GET https://api.first.org/data/v1/epss?percentile-gt=0.95`
|
||||
- **Full download**: `https://epss.cyentia.com/epss_scores-current.csv.gz`
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
# Workflows - EPSS Vulnerability Prioritization
|
||||
|
||||
## Workflow 1: Daily EPSS Enrichment Pipeline
|
||||
|
||||
### Steps
|
||||
1. Download full EPSS dataset from https://epss.cyentia.com/epss_scores-current.csv.gz
|
||||
2. Load into local database for fast lookups
|
||||
3. Query open vulnerabilities from vulnerability management platform
|
||||
4. Enrich each CVE with current EPSS score and percentile
|
||||
5. Apply priority matrix combining EPSS and CVSS scores
|
||||
6. Update priority fields in DefectDojo/Jira/tracking system
|
||||
7. Alert on any CVEs that crossed EPSS threshold (e.g., jumped above 0.4)
|
||||
|
||||
## Workflow 2: EPSS Spike Detection
|
||||
|
||||
### Steps
|
||||
1. Compare today's EPSS scores against yesterday's scores for all open CVEs
|
||||
2. Identify CVEs with EPSS increase > 0.2 in past 24 hours
|
||||
3. Cross-reference spike CVEs with asset inventory
|
||||
4. Send high-priority alert for spiking CVEs affecting production assets
|
||||
5. Automatically escalate to P1 if EPSS crosses 0.7 threshold
|
||||
|
||||
## Workflow 3: Prioritized Remediation Report
|
||||
|
||||
### Steps
|
||||
1. Pull all open vulnerabilities from scanner
|
||||
2. Enrich with EPSS scores and CISA KEV membership
|
||||
3. Apply combined EPSS + CVSS + KEV priority matrix
|
||||
4. Group by priority tier (P0-P4)
|
||||
5. Within each tier, sort by EPSS score descending
|
||||
6. Generate report showing estimated risk reduction per remediation action
|
||||
7. Distribute to asset owners with assigned remediation timelines
|
||||
@@ -0,0 +1,215 @@
|
||||
#!/usr/bin/env python3
|
||||
"""EPSS Vulnerability Prioritization Tool.
|
||||
|
||||
Fetches EPSS scores from FIRST API and prioritizes vulnerabilities
|
||||
using a combined EPSS + CVSS matrix approach.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import csv
|
||||
import gzip
|
||||
import io
|
||||
import json
|
||||
import sys
|
||||
import time
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
|
||||
import requests
|
||||
|
||||
EPSS_API = "https://api.first.org/data/v1/epss"
|
||||
EPSS_BULK_URL = "https://epss.cyentia.com/epss_scores-current.csv.gz"
|
||||
KEV_URL = "https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json"
|
||||
|
||||
PRIORITY_MAP = {
|
||||
"P0": {"label": "Immediate", "sla_hours": 24},
|
||||
"P1": {"label": "Urgent", "sla_hours": 48},
|
||||
"P2": {"label": "High", "sla_days": 7},
|
||||
"P3": {"label": "Medium", "sla_days": 30},
|
||||
"P4": {"label": "Low", "sla_days": 90},
|
||||
}
|
||||
|
||||
|
||||
def fetch_epss_bulk():
|
||||
"""Download full EPSS dataset for local lookups."""
|
||||
print("[*] Downloading full EPSS dataset...")
|
||||
resp = requests.get(EPSS_BULK_URL, timeout=60)
|
||||
resp.raise_for_status()
|
||||
content = gzip.decompress(resp.content).decode("utf-8")
|
||||
reader = csv.DictReader(io.StringIO(content))
|
||||
scores = {}
|
||||
for row in reader:
|
||||
cve = row.get("cve", "").strip()
|
||||
if cve:
|
||||
scores[cve] = {
|
||||
"epss": float(row.get("epss", 0)),
|
||||
"percentile": float(row.get("percentile", 0)),
|
||||
}
|
||||
print(f" Loaded EPSS scores for {len(scores)} CVEs")
|
||||
return scores
|
||||
|
||||
|
||||
def fetch_epss_api(cve_list):
|
||||
"""Fetch EPSS scores for specific CVEs via API."""
|
||||
scores = {}
|
||||
batch_size = 100
|
||||
for i in range(0, len(cve_list), batch_size):
|
||||
batch = cve_list[i : i + batch_size]
|
||||
try:
|
||||
resp = requests.get(
|
||||
EPSS_API, params={"cve": ",".join(batch)}, timeout=30
|
||||
)
|
||||
if resp.status_code == 200:
|
||||
for entry in resp.json().get("data", []):
|
||||
scores[entry["cve"]] = {
|
||||
"epss": float(entry.get("epss", 0)),
|
||||
"percentile": float(entry.get("percentile", 0)),
|
||||
}
|
||||
except requests.RequestException as e:
|
||||
print(f"[-] EPSS API error: {e}")
|
||||
time.sleep(0.5)
|
||||
return scores
|
||||
|
||||
|
||||
def fetch_kev_catalog():
|
||||
"""Download CISA KEV catalog."""
|
||||
resp = requests.get(KEV_URL, timeout=30)
|
||||
resp.raise_for_status()
|
||||
return {v["cveID"] for v in resp.json().get("vulnerabilities", [])}
|
||||
|
||||
|
||||
def assign_priority(epss_score, cvss_score, in_kev=False):
|
||||
"""Assign priority based on EPSS + CVSS + KEV matrix."""
|
||||
if in_kev:
|
||||
if cvss_score >= 9.0:
|
||||
return "P0"
|
||||
return "P1"
|
||||
if epss_score > 0.7 and cvss_score >= 9.0:
|
||||
return "P0"
|
||||
if epss_score > 0.7 and cvss_score >= 7.0:
|
||||
return "P1"
|
||||
if epss_score > 0.4 and cvss_score >= 7.0:
|
||||
return "P2"
|
||||
if epss_score > 0.1 or cvss_score >= 7.0:
|
||||
return "P3"
|
||||
return "P4"
|
||||
|
||||
|
||||
def prioritize_scan_results(input_csv, output_csv, use_bulk=False):
|
||||
"""Enrich vulnerability scan results with EPSS and prioritize."""
|
||||
vulnerabilities = []
|
||||
with open(input_csv, "r", encoding="utf-8") as f:
|
||||
reader = csv.DictReader(f)
|
||||
for row in reader:
|
||||
vulnerabilities.append(row)
|
||||
|
||||
cve_list = list({v.get("cve_id", "") for v in vulnerabilities if v.get("cve_id")})
|
||||
print(f"[*] Processing {len(vulnerabilities)} findings ({len(cve_list)} unique CVEs)")
|
||||
|
||||
if use_bulk:
|
||||
epss_scores = fetch_epss_bulk()
|
||||
else:
|
||||
epss_scores = fetch_epss_api(cve_list)
|
||||
|
||||
print("[*] Fetching CISA KEV catalog...")
|
||||
kev_set = fetch_kev_catalog()
|
||||
print(f" {len(kev_set)} CVEs in KEV catalog")
|
||||
|
||||
results = []
|
||||
for vuln in vulnerabilities:
|
||||
cve_id = vuln.get("cve_id", "")
|
||||
cvss = float(vuln.get("cvss_score", 0))
|
||||
epss_data = epss_scores.get(cve_id, {"epss": 0, "percentile": 0})
|
||||
in_kev = cve_id in kev_set
|
||||
priority = assign_priority(epss_data["epss"], cvss, in_kev)
|
||||
|
||||
results.append({
|
||||
**vuln,
|
||||
"epss_score": round(epss_data["epss"], 5),
|
||||
"epss_percentile": round(epss_data["percentile"], 5),
|
||||
"in_cisa_kev": in_kev,
|
||||
"priority": priority,
|
||||
"priority_label": PRIORITY_MAP[priority]["label"],
|
||||
})
|
||||
|
||||
results.sort(key=lambda r: (
|
||||
{"P0": 0, "P1": 1, "P2": 2, "P3": 3, "P4": 4}[r["priority"]],
|
||||
-r["epss_score"],
|
||||
))
|
||||
|
||||
if results:
|
||||
with open(output_csv, "w", newline="", encoding="utf-8") as f:
|
||||
writer = csv.DictWriter(f, fieldnames=results[0].keys())
|
||||
writer.writeheader()
|
||||
writer.writerows(results)
|
||||
|
||||
priority_counts = {}
|
||||
for r in results:
|
||||
p = r["priority"]
|
||||
priority_counts[p] = priority_counts.get(p, 0) + 1
|
||||
|
||||
print(f"\n[+] Prioritization Results -> {output_csv}")
|
||||
for p in ["P0", "P1", "P2", "P3", "P4"]:
|
||||
count = priority_counts.get(p, 0)
|
||||
print(f" {p} ({PRIORITY_MAP[p]['label']}): {count}")
|
||||
print(f" KEV matches: {sum(1 for r in results if r['in_cisa_kev'])}")
|
||||
return results
|
||||
|
||||
|
||||
def detect_epss_spikes(previous_csv, current_scores, threshold=0.2):
|
||||
"""Compare EPSS scores to detect significant increases."""
|
||||
previous = {}
|
||||
with open(previous_csv, "r", encoding="utf-8") as f:
|
||||
reader = csv.DictReader(f)
|
||||
for row in reader:
|
||||
cve = row.get("cve_id", "")
|
||||
if cve:
|
||||
previous[cve] = float(row.get("epss_score", 0))
|
||||
|
||||
spikes = []
|
||||
for cve, prev_score in previous.items():
|
||||
current = current_scores.get(cve, {}).get("epss", 0)
|
||||
increase = current - prev_score
|
||||
if increase >= threshold:
|
||||
spikes.append({
|
||||
"cve_id": cve,
|
||||
"previous_epss": prev_score,
|
||||
"current_epss": current,
|
||||
"increase": round(increase, 5),
|
||||
})
|
||||
|
||||
spikes.sort(key=lambda s: s["increase"], reverse=True)
|
||||
if spikes:
|
||||
print(f"\n[!] EPSS Spikes Detected ({len(spikes)} CVEs):")
|
||||
for s in spikes[:20]:
|
||||
print(f" {s['cve_id']}: {s['previous_epss']:.4f} -> {s['current_epss']:.4f} (+{s['increase']:.4f})")
|
||||
return spikes
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="EPSS Vulnerability Prioritization Tool")
|
||||
parser.add_argument("--input", help="Input CSV with vulnerability scan results")
|
||||
parser.add_argument("--output", default="epss_prioritized.csv", help="Output prioritized CSV")
|
||||
parser.add_argument("--bulk", action="store_true", help="Use bulk EPSS download instead of API")
|
||||
parser.add_argument("--detect-spikes", help="Previous results CSV for spike detection")
|
||||
parser.add_argument("--spike-threshold", type=float, default=0.2, help="EPSS increase threshold")
|
||||
parser.add_argument("--query", help="Query EPSS for specific CVE(s), comma-separated")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.query:
|
||||
cves = [c.strip() for c in args.query.split(",")]
|
||||
scores = fetch_epss_api(cves)
|
||||
for cve, data in scores.items():
|
||||
pct = data["epss"] * 100
|
||||
print(f"{cve}: {pct:.2f}% exploitation probability (percentile: {data['percentile']:.4f})")
|
||||
elif args.input:
|
||||
results = prioritize_scan_results(args.input, args.output, args.bulk)
|
||||
if args.detect_spikes:
|
||||
current_scores = {r["cve_id"]: {"epss": r["epss_score"]} for r in results if r.get("cve_id")}
|
||||
detect_epss_spikes(args.detect_spikes, current_scores, args.spike_threshold)
|
||||
else:
|
||||
parser.print_help()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user