Docs / Cyber Threat Data API
Cyber Threat Data API
Two feeds that answer different halves of one question. CISA's Known Exploited Vulnerabilities catalog says what is being exploited now: every CVE the agency has evidence of active exploitation for, with the Binding Operational Directive action and deadline attached to each one — 1,716 entries in the catalog current in September 2026 and all of them served. Every row names the published catalog version it came from and every version we have fetched is kept, so “what did this deadline say in August” is answerable rather than lost; a request that names no catalog always gets the current one. FIRST's EPSS scores say what is likely to be exploited next: a probability for the coming 30 days, for every published CVE, looked up by id in batches of up to a hundred rather than paged. That is deliberate — it is over 377,000 scores rewritten every night, and the daily file FIRST publishes is the right way to take all of them, so the snapshot endpoint hands you its address. A CVE with no score comes back in an explicit not_found list rather than as a silently shorter answer. The KEV catalog is a work of the United States Government, public domain under 17 U.S.C. 105, and CISA states no redistribution restriction on the feed. EPSS is published by FIRST under CC BY 4.0: if you publish those scores onward, reproduce the attribution string the snapshot endpoint serves.
Endpoints
| Endpoint | Route | Returns |
|---|---|---|
| List exploited vulnerabilities | GET /v1/cyber/kev |
collection |
| Retrieve a catalogued vulnerability | GET /v1/cyber/kev/{id} |
single object |
| Score a list of CVEs | GET /v1/cyber/epss |
collection |
| Which score set is served | GET /v1/cyber/epss/snapshot |
single object |
The Cyber object
The fields below appear on the dataset's primary resource. Endpoint pages list any fields specific to them.
| Field | Type | Description |
|---|---|---|
id |
string | Stable identifier, "<source>:<catalog version>:<CVE id>" — `cisa_kev:2026.09.18:CVE-2025-39964`. Opaque: treat the whole string as the id rather than parsing the parts out of it. **It names a SNAPSHOT of a CVE, not the CVE** — the same CVE has a different id in every catalog version that lists it, so an id you stored keeps resolving to the `due_date` you saw rather than silently moving to a newer one. |
source |
string | Which scraper delivered this catalog. `cisa_kev` is CISA's own published feed. |
catalog_version |
string | CISA's own version label for the published document — `2026.09.18`. Treat it as opaque rather than as a date: it is the publisher's rendering, and `date_released` is the fact. **Pass it back as `?catalog_version=` to pin a walk to one snapshot.** |
date_released |
timestamp | When that catalog was published. A real instant with a time of day in it, not a date — the measured release was 19:00:05 UTC. |
catalog_count |
integer | CISA's own count of the records in that document, **verbatim and never reconciled** with the number of rows served. It has agreed on every fetch measured; if it ever does not, that disagreement is a fact about the upstream document and replacing it with our arithmetic would delete the only evidence of it. |
cve_id |
string | The CVE identifier, `CVE-2025-39964`. **The year in it is the year the CVE was assigned, not the year CISA catalogued it** — `CVE-2002-0367` was added to this catalog in 2022. `date_added` is the other fact and neither is derivable from the other. |
vendor_project |
string · nullable | The upstream's own label for the vendor or project — `Microsoft`, `Linux`, `Cisco`. Free text rather than a taxonomy this platform maintains, so `?vendor=` is a case-insensitive EXACT match: `Apache` and `Apache Tomcat` are two entries here and this API will not collapse them for you. |
product |
string · nullable | The upstream's own label for the affected product. |
vulnerability_name |
string · nullable | CISA's short title for the vulnerability. |
date_added |
date · nullable | The day CISA added this CVE to the catalog. **This is the watermark to sync on** — "what has been catalogued since Tuesday" is a question about the catalogue, where `ingested_at` is a question about us. `?added_from=` takes it. |
due_date |
date · nullable | The Binding Operational Directive deadline for `required_action`. **`?due_to=<today>` is how you ask what is past it.** |
short_description |
string · nullable | CISA's own summary of the vulnerability. |
required_action |
string · nullable | The BOD instruction, verbatim and at length. It usually names the directive it comes from and points at `notes` for the URL. Together with `due_date` this is what makes a row a compliance instrument rather than a vulnerability description — and what makes a stale copy of one harmful rather than merely old. |
known_ransomware_campaign_use |
string | `Known` or `Unknown`, **CISA's own value and not a boolean**. `Unknown` is the agency saying it has no evidence of ransomware use — not that there is none — so publishing it as `false` would put our coercion out under their name. 360 of 1,716 were `Known` on the measured catalog. `?ransomware=known` takes the same vocabulary, lower-cased. |
forensic_triage |
string | `Yes` or `No`, CISA's own value. This one genuinely is a boolean and is still carried as published, so this collection has one rule rather than two. |
notes |
string · nullable | CISA's free-text note, usually carrying the vendor advisory URL and the BOD reference. |
cwes |
array of string · nullable | The upstream's CWE identifiers, `["CWE-362"]`. **An empty array and `null` mean different things and both occur**: `[]` is "CISA classified this and named no weakness" (175 of 1,716 on the measured catalog) and `null` is "CISA did not carry the field". They are not collapsed. |
ingested_at |
timestamp | When this platform stored this snapshot. A whole catalog arrives in one batch, so every row of one `catalog_version` shares this to the microsecond — it dates the snapshot, not the record. |