Initial commit - 611 cybersecurity skills across all subdomains

This commit is contained in:
mukul975
2026-02-25 10:47:44 +01:00
commit 22a7ab1462
1765 changed files with 280648 additions and 0 deletions
@@ -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 |
@@ -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`
@@ -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()