Exploitability
Get EPSS (Exploit Prediction Scoring System) scores and CISA KEV (Known Exploited Vulnerabilities) data for tracked CVEs.
Endpoint
GET /api/v1/exploitabilityResponse
{
"success": true,
"data": {
"epss": {
"scores": {
"CVE-2024-1234": {
"epss": 0.42,
"percentile": 0.97
}
},
"lastUpdated": "2026-02-10T12:00:00.000Z",
"totalCVEs": 150,
"enrichedCount": 120,
"highRiskCount": 15
},
"kev": {
"kevMap": {
"CVE-2024-1234": {
"vendorProject": "openssl",
"product": "OpenSSL",
"dateAdded": "2024-03-15",
"dueDate": "2024-04-05",
"knownRansomwareCampaignUse": "Unknown"
}
},
"catalogVersion": "2026.02.10",
"dateReleased": "2026-02-10",
"totalEntries": 1200,
"matchingTracked": 5,
"lastUpdated": "2026-02-10T12:00:00.000Z"
}
},
"timestamp": "2026-02-10T12:00:00.000Z"
}Response Fields
EPSS Object
| Field | Type | Description |
|---|---|---|
scores | object | Map of CVE ID to EPSS score and percentile |
lastUpdated | string | When EPSS data was last refreshed |
totalCVEs | number | Total tracked CVEs |
enrichedCount | number | CVEs with EPSS data |
highRiskCount | number | CVEs with EPSS > 0.5 (high exploitability) |
KEV Object
| Field | Type | Description |
|---|---|---|
kevMap | object | Map of CVE ID to CISA KEV entry |
catalogVersion | string | CISA KEV catalog version |
totalEntries | number | Total entries in KEV catalog |
matchingTracked | number | How many tracked CVEs appear in KEV |
lastUpdated | string | When KEV data was last refreshed |
Partial answers
data.partial is true when one of the two sources could not be read. The block that failed then carries available: false with every count null rather than zero, so kevMap: null next to partial: true means the catalogue was not consulted, not that nothing tracked is in it. Both blocks carry available in every answer.
Example
curl https://api.vulnpatch.dev/api/v1/exploitabilityCode Examples
async function getExploitability() {
const response = await fetch('https://api.vulnpatch.dev/api/v1/exploitability');
const { data } = await response.json();
// High-risk CVEs by EPSS
const highRisk = Object.entries(data.epss.scores)
.filter(([, s]) => s.epss >= 0.5)
.sort((a, b) => b[1].epss - a[1].epss);
console.log(`High risk CVEs: ${highRisk.length}`);
console.log(`In CISA KEV: ${data.kev.matchingTracked}`);
}import requests
response = requests.get("https://api.vulnpatch.dev/api/v1/exploitability")
data = response.json()["data"]
# High-risk CVEs
high_risk = {cve: s for cve, s in data["epss"]["scores"].items() if s["epss"] >= 0.5}
print(f"High risk: {len(high_risk)}")
print(f"In CISA KEV: {data['kev']['matchingTracked']}")Per-CVE Exploitability
EPSS and KEV data is also returned inline on individual CVE lookups via GET /api/v1/cve/:id. The response includes data.epss and data.kev fields when available, so you don't need to call this bulk endpoint for single-CVE lookups.
# Get EPSS + KEV inline with CVE data
curl -s "https://api.vulnpatch.dev/api/v1/cve/CVE-2024-3094" | jq '{epss: .data.epss, kev: .data.kev}'Exploit maturity on the dossier
GET /api/v1/cve/:id/dossier carries canonical.exploitMaturity: how far exploitation has been shown to go, from CISA KEV, CISA's SSVC decision, Exploit-DB, the Metasploit Framework, Nuclei templates and GitHub search.
level | Meaning |
|---|---|
active | In CISA KEV, or CISA's SSVC decision says exploitation is active |
poc | Public exploit code or a detection template: an Exploit-DB entry, a Metasploit exploit module, a Nuclei template, a GitHub proof-of-concept repository or SSVC says poc |
unreported | Every source answered and none matched |
unknown | A source did not answer; sourcesUnreached names it |
unreported and unknown are different answers. A fetch that failed has not said "no exploit", and an agent reading unknown as unreported acts past an exploit a failure hid.
Each artefact block (exploitdb, metasploit, nuclei, githubPoc) is null when its source did not answer, and otherwise lists up to ten items with the total stated. What is republished is identifiers, names, dates, ranks and links: an Exploit-DB entry as {edbId, title, datePublished, verified, type, platform, url}, a Metasploit module as {fullname, rank, rankName, disclosureDate, type, url}, a Nuclei template as its page in projectdiscovery/nuclei-templates, a GitHub repository as its name, link and stars. Exploit code, template bodies and comment text are never republished. Only a Metasploit module of type exploit counts towards poc; an auxiliary or post module scans, checks or acts after access, and is listed as such.
Each exploit source appears in the dossier's provenance with its licence and attribution: Exploit-DB (OffSec) under GPL-2.0, the Metasploit Framework under BSD-3-Clause (Copyright 2006-2026, Rapid7, Inc.; Rapid7 does not endorse this service), nuclei-templates under MIT (Copyright (c) 2025 ProjectDiscovery, Inc.) and GitHub repositories each under their own licence.
The Exploit-DB and Metasploit indexes are rebuilt by the scheduler from files_exploits.csv and modules_metadata_base.json, daily and weekly. A rebuild that fails leaves the previous index in place for a bounded time, after which lookups report the source as unreached rather than answer from stale data.
Use Cases
- Prioritization: Rank CVEs by real-world exploitability (EPSS) rather than just CVSS
- Compliance: Identify CVEs in CISA KEV that require mandatory remediation
- Risk assessment: Combine EPSS with severity for a more complete risk picture
Related Endpoints
GET /api/v1/cve/:id- Single CVE lookup (includes inline EPSS + KEV)GET /api/v1/fix-etas- Predicted fix timelinesGET /api/v1/rebuild-impact- Rebuild blast radiusGET /api/v1/analytics- CVE analytics aggregates