Performing CVE Prioritization with KEV Catalog
Overview
The CISA Known Exploited Vulnerabilities (KEV) catalog, established through Binding Operational Directive (BOD) 22-01, is a living list of CVEs that have been actively exploited in the wild and carry significant risk. As of early 2026, the catalog contains over 1,484 entries, growing 20% in 2025 alone with 245 new additions. This guide covers integrating the KEV catalog into vulnerability prioritization workflows alongside EPSS (Exploit Prediction Scoring System) and CVSS to create a risk-based approach that prioritizes vulnerabilities with confirmed exploitation activity over theoretical severity alone.
Prerequisites
- Access to vulnerability scan results (Qualys, Nessus, Rapid7, etc.)
- Familiarity with CVE identifiers and NVD
- Understanding of CVSS scoring (v3.1 and v4.0)
- API access to CISA KEV, EPSS, and NVD endpoints
- Python 3.8+ with requests and pandas libraries
Core Concepts
CISA KEV Catalog Structure
Each KEV entry contains:
- CVE ID: The CVE identifier (e.g., CVE-2024-3094)
- Vendor/Project: Affected vendor and product name
- Vulnerability Name: Short description of the vulnerability
- Date Added: When CISA added it to the catalog
- Short Description: Brief technical description
- Required Action: Recommended remediation action
- Due Date: Deadline for federal agencies (FCEB) to remediate
- Known Ransomware Campaign Use: Whether ransomware groups exploit it
BOD 22-01 Remediation Timelines
| CVE Publication Date | Remediation Deadline |
|---|---|
| 2021 or later | 2 weeks from KEV listing |
| Before 2021 | 6 months from KEV listing |
Multi-Factor Prioritization Model
| Factor | Weight | Data Source | Rationale |
|---|---|---|---|
| CISA KEV Listed | 30% | CISA KEV JSON feed | Confirmed active exploitation |
| EPSS Score | 25% | FIRST EPSS API | Predicted exploitation probability |
| CVSS Base Score | 20% | NVD API v2.0 | Intrinsic vulnerability severity |
| Asset Criticality | 15% | CMDB/Asset inventory | Business impact context |
| Network Exposure | 10% | Network architecture | Attack surface accessibility |
KEV + EPSS Decision Matrix
| KEV Listed | EPSS > 0.5 | CVSS >= 9.0 | Priority | SLA |
|---|---|---|---|---|
| Yes | Any | Any | P1-Emergency | 48 hours |
| No | Yes | Yes | P1-Emergency | 48 hours |
| No | Yes | No | P2-Critical | 7 days |
| No | No | Yes | P2-Critical | 7 days |
| No | No | No (>= 7.0) | P3-High | 14 days |
| No | No | No (>= 4.0) | P4-Medium | 30 days |
| No | No | No (< 4.0) | P5-Low | 90 days |
Implementation Steps
Step 1: Fetch and Parse the KEV Catalog
import requests
import json
from datetime import datetime
KEV_URL = "https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json"
def fetch_kev_catalog():
"""Download and parse the CISA KEV catalog."""
response = requests.get(KEV_URL, timeout=30)
response.raise_for_status()
data = response.json()
catalog = {}
for vuln in data.get("vulnerabilities", []):
cve_id = vuln["cveID"]
catalog[cve_id] = {
"vendor": vuln.get("vendorProject", ""),
"product": vuln.get("product", ""),
"name": vuln.get("vulnerabilityName", ""),
"date_added": vuln.get("dateAdded", ""),
"description": vuln.get("shortDescription", ""),
"action": vuln.get("requiredAction", ""),
"due_date": vuln.get("dueDate", ""),
"ransomware_use": vuln.get("knownRansomwareCampaignUse", "Unknown"),
}
print(f"[+] Loaded {len(catalog)} CVEs from CISA KEV catalog")
print(f" Catalog version: {data.get('catalogVersion', 'N/A')}")
print(f" Last updated: {data.get('dateReleased', 'N/A')}")
return catalog
kev = fetch_kev_catalog()
Step 2: Enrich with EPSS Scores
EPSS_API = "https://api.first.org/data/v1/epss"
def get_epss_scores(cve_list):
"""Fetch EPSS scores for a batch of CVEs."""
scores = {}
batch_size = 100
for i in range(0, len(cve_list), batch_size):
batch = cve_list[i:i + batch_size]
cve_param = ",".join(batch)
response = requests.get(EPSS_API, params={"cve": cve_param}, timeout=30)
if response.status_code == 200:
for entry in response.json().get("data", []):
scores[entry["cve"]] = {
"epss": float(entry.get("epss", 0)),
"percentile": float(entry.get("percentile", 0)),
}
return scores
Step 3: Build the Prioritization Engine
import pandas as pd
def prioritize_vulnerabilities(scan_results, kev_catalog, epss_scores):
"""Apply multi-factor prioritization to scan results."""
prioritized = []
for vuln in scan_results:
cve_id = vuln.get("cve_id", "")
cvss_score = float(vuln.get("cvss_score", 0))
asset_criticality = float(vuln.get("asset_criticality", 3))
exposure = float(vuln.get("network_exposure", 3))
in_kev = cve_id in kev_catalog
kev_data = kev_catalog.get(cve_id, {})
epss_data = epss_scores.get(cve_id, {"epss": 0, "percentile": 0})
epss_score = epss_data["epss"]
# Composite risk score calculation
risk_score = (
(1.0 if in_kev else 0.0) * 10 * 0.30 +
epss_score * 10 * 0.25 +
cvss_score * 0.20 +
(asset_criticality / 5.0) * 10 * 0.15 +
(exposure / 5.0) * 10 * 0.10
)
# Assign priority level
if in_kev or (epss_score > 0.5 and cvss_score >= 9.0):
priority = "P1-Emergency"
sla_days = 2
elif epss_score > 0.5 or cvss_score >= 9.0:
priority = "P2-Critical"
sla_days = 7
elif cvss_score >= 7.0:
priority = "P3-High"
sla_days = 14
elif cvss_score >= 4.0:
priority = "P4-Medium"
sla_days = 30
else:
priority = "P5-Low"
sla_days = 90
prioritized.append({
"cve_id": cve_id,
"cvss_score": cvss_score,
"epss_score": round(epss_score, 4),
"epss_percentile": round(epss_data["percentile"], 4),
"in_cisa_kev": in_kev,
"ransomware_use": kev_data.get("ransomware_use", "N/A"),
"kev_due_date": kev_data.get("due_date", "N/A"),
"risk_score": round(risk_score, 2),
"priority": priority,
"sla_days": sla_days,
"asset": vuln.get("asset", ""),
"asset_criticality": asset_criticality,
})
df = pd.DataFrame(prioritized)
df = df.sort_values("risk_score", ascending=False)
return df
Step 4: Generate Prioritization Report
def generate_report(df, output_file="kev_prioritized_report.csv"):
"""Generate summary report from prioritized vulnerabilities."""
print("\n" + "=" * 70)
print("VULNERABILITY PRIORITIZATION REPORT - KEV + EPSS + CVSS")
print("=" * 70)
print(f"\nTotal vulnerabilities analyzed: {len(df)}")
print(f"KEV-listed vulnerabilities: {df['in_cisa_kev'].sum()}")
print(f"Ransomware-associated: {(df['ransomware_use'] == 'Known').sum()}")
print("\nPriority Distribution:")
print(df["priority"].value_counts().to_string())
print("\nTop 15 Highest Risk Vulnerabilities:")
top = df.head(15)[["cve_id", "cvss_score", "epss_score", "in_cisa_kev",
"risk_score", "priority"]]
print(top.to_string(index=False))
df.to_csv(output_file, index=False)
print(f"\n[+] Full report saved to: {output_file}")
Best Practices
- Update the KEV catalog daily since CISA adds new entries multiple times per week
- Always cross-reference KEV with EPSS; a CVE may have high EPSS but not yet be in KEV
- Treat all KEV-listed CVEs as P1-Emergency regardless of CVSS score
- Pay special attention to KEV entries flagged with "Known Ransomware Campaign Use"
- Automate KEV comparison against your vulnerability scan results in CI/CD pipelines
- Track KEV due dates separately for FCEB compliance requirements
- Use KEV as a leading indicator for threat hunting; if a CVE is added, check for prior exploitation in your environment
Common Pitfalls
- Relying solely on CVSS scores without checking KEV or EPSS data
- Not updating the KEV catalog frequently enough (CISA updates multiple times weekly)
- Treating non-KEV CVEs as safe; they may be exploited but not yet cataloged
- Ignoring the "ransomware use" field which indicates highest-urgency threats
- Using KEV only for compliance instead of integrating into overall risk management
Related Skills
- prioritizing-vulnerabilities-with-cvss-scoring
- building-vulnerability-data-pipeline-with-api
- implementing-threat-intelligence-scoring
- implementing-vulnerability-remediation-sla
Verification Criteria
Confirm successful execution by validating:
- [ ] All prerequisite tools and access requirements are satisfied
- [ ] Each workflow step completed without errors
- [ ] Output matches expected format and contains expected data
- [ ] No security warnings or misconfigurations detected
- [ ] Results are documented and evidence is preserved for audit
Compliance Framework Mapping
This skill supports compliance evidence collection across multiple frameworks:
- SOC 2: CC7.1 (Monitoring), CC8.1 (Change Management)
- ISO 27001: A.12.6 (Technical Vulnerability Management)
- NIST 800-53: RA-5 (Vulnerability Scanning), SI-2 (Flaw Remediation), CM-6 (Configuration Settings)
- NIST CSF: ID.RA (Risk Assessment), PR.IP (Information Protection)
Claw GRC Tip: When this skill is executed by a registered agent, compliance evidence is automatically captured and mapped to the relevant controls in your active frameworks.
Deploying This Skill with Claw GRC
Agent Execution
Register this skill with your Claw GRC agent for automated execution:
# Install via CLI
npx claw-grc skills add performing-cve-prioritization-with-kev-catalog
# Or load dynamically via MCP
grc.load_skill("performing-cve-prioritization-with-kev-catalog")
Audit Trail Integration
When executed through Claw GRC, every step of this skill generates tamper-evident audit records:
- SHA-256 chain hashing ensures no step can be modified after execution
- Evidence artifacts (configs, scan results, logs) are automatically attached to relevant controls
- Trust score impact — successful execution increases your agent's trust score
Continuous Compliance
Schedule this skill for recurring execution to maintain continuous compliance posture. Claw GRC monitors for drift and alerts when re-execution is needed.