# CVE Triage | KEV + EPSS Exploit Risk, Not Just CVSS (`alinz/cve-triage`) Actor

Vulnerability triage that answers which CVEs actually matter. Joins NVD severity with EPSS exploit probability and CISA's Known Exploited Vulnerabilities catalogue, including the ransomware-campaign flag, and ranks every CVE by real-world exploitation risk.

- **URL**: https://apify.com/alinz/cve-triage.md
- **Developed by:** [אלון זריהן](https://apify.com/alinz) (community)
- **Categories:** Developer tools, AI, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $6.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## CVE Triage — Which Vulnerabilities Actually Matter

Severity does not tell you what to patch. This Actor joins three open feeds that, together, do:

| Feed | What it contributes |
|---|---|
| **NVD** | CVSS severity, affected products, references |
| **EPSS** | Probability the CVE will be exploited in the next 30 days |
| **CISA KEV** | Confirmed exploitation in the wild, plus the ransomware-campaign flag |

Every other vulnerability Actor scrapes one of these. Joining them is the point.

### The problem this solves

On a live sample of 56 CVEs rated **CVSS 9.0 or higher**, **35 of them — 63% — had an EPSS score below 1% and no record of exploitation**. They were, in practice, not urgent.

A raw NVD feed hands you all 56 and calls them critical. This Actor tells you which 21 to look at first.

### Priority ranking

Each CVE is assigned one of four bands, and the rule is stated plainly rather than hidden in a score:

| Priority | Meaning |
|---|---|
| **ACTIVELY\_EXPLOITED** | On CISA's KEV list. Someone is exploiting this right now. |
| **PROBABLE** | EPSS ≥ 10%. Exploitation is likely within 30 days. |
| **ELEVATED** | EPSS ≥ 1%, or critical severity with a real exploit signal. |
| **STANDARD** | Everything else, whatever CVSS says. |

Rows come back sorted most-urgent-first, so capping results still returns the ones that matter.

### Modes

**`kev` — actively exploited (recommended).** CISA's entire Known Exploited Vulnerabilities catalogue, ~1,685 CVEs, enriched with EPSS scores and full NVD detail. The highest-signal vulnerability list that exists.

**`recent` — newly published.** Triage the CVE firehose. Roughly 6,000 CVEs are published every two weeks; a `minEpss` of 0.05 typically reduces that to a handful.

**`search` — by vendor or product.** Every Fortinet, WordPress, Citrix or Apache CVE, ranked by exploitation risk rather than by severity.

### Examples

**Ransomware-linked vulnerabilities — the shortest, sharpest list:**

```json
{ "mode": "kev", "ransomwareOnly": true }
```

**What actually needs attention this month:**

```json
{ "mode": "recent", "daysBack": 30, "minEpss": 0.05 }
```

**Everything affecting a vendor, urgent first:**

```json
{ "mode": "search", "keyword": "fortinet", "includeStandard": false }
```

**Your weekly patch list:**

```json
{ "mode": "kev", "minEpss": 0.1, "maxResults": 50 }
```

### Output

```json
{
  "cveId": "CVE-2021-44228",
  "priority": "ACTIVELY_EXPLOITED",
  "priorityRank": 1,
  "knownExploited": true,
  "knownRansomware": true,
  "epssScore": 0.99999,
  "epssPercentile": 0.99975,
  "kevDateAdded": "2021-12-10",
  "kevDueDate": "2021-12-24",
  "kevRequiredAction": "Apply updates per vendor instructions.",
  "cvssScore": 10.0,
  "cvssSeverity": "CRITICAL",
  "cvssVersion": "3.1",
  "cvssVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
  "published": "2021-12-10T10:15:09.143",
  "vendorProject": "Apache",
  "product": "Log4j2",
  "cwes": ["CWE-502", "CWE-400", "CWE-20"],
  "description": "Apache Log4j2 2.0-beta9 through 2.15.0 ...",
  "referenceCount": 103,
  "nvdUrl": "https://nvd.nist.gov/vuln/detail/CVE-2021-44228"
}
```

### Field reference

| Field | Meaning |
|---|---|
| `priority` / `priorityRank` | Triage band and its sort order (1 = most urgent) |
| `knownExploited` | Present in CISA's KEV catalogue |
| `knownRansomware` | CISA has linked it to a ransomware campaign |
| `epssScore` | Probability of exploitation within 30 days, 0-1 |
| `epssPercentile` | Rank against all ~366,000 scored CVEs |
| `kevDateAdded` / `kevDueDate` | When CISA listed it, and the federal remediation deadline |
| `kevRequiredAction` | The remediation CISA specifies |
| `cvssScore` / `cvssSeverity` / `cvssVector` | Severity, from the newest CVSS version NVD publishes |
| `vendorProject` / `product` | Vendor and product, from the KEV entry |
| `cwes` | Weakness classifications |
| `published` / `lastModified` / `vulnStatus` | NVD lifecycle fields |
| `referenceCount` / `references` | Advisory links (first five) |

### Notes on the data

- **EPSS is a probability, not a verdict.** A score of 0.10 means roughly a one-in-ten chance of observed exploitation within 30 days. It is a prioritisation aid, not a guarantee in either direction.
- **EPSS is re-scored daily**, so results shift between runs. Each run records the model date in `RUN_STATS`.
- **KEV is authoritative but lagging.** A CVE appears once CISA has confirmed exploitation, which is after exploitation began. Absence from KEV is not evidence of safety — that is precisely what EPSS is for.
- **Some CVEs have no EPSS score**, usually very new or rejected entries. Setting `minEpss` excludes them.
- **CVSS versions differ across records.** The newest available is used, preferring 4.0 over 3.1 over 3.0 over 2.0, and the version is reported per row.
- **NVD limits date windows to 120 days**; the Actor rejects wider ranges rather than silently truncating.

### Sources and conduct

All three feeds are public and require no authentication:

- [NVD](https://nvd.nist.gov/developers/vulnerabilities) — NIST National Vulnerability Database
- [EPSS](https://www.first.org/epss/) — FIRST Exploit Prediction Scoring System
- [CISA KEV](https://www.cisa.gov/known-exploited-vulnerabilities-catalog) — Known Exploited Vulnerabilities catalogue

Requests are rate-limited and backed off politely; NVD in particular is a free public service and this Actor pauses between pages rather than hammering it. Nothing here bypasses an access control.

### Integrations

Output lands in a standard Apify dataset: export as **JSON, CSV, Excel or XML**, or wire it into **Make, Zapier, n8n, Slack, Jira** or your own code via the Apify API. Schedule it daily and alert on new `ACTIVELY_EXPLOITED` rows.

# Actor input Schema

## `mode` (type: `string`):

'Actively exploited' returns CISA's full KEV catalogue enriched with EPSS and NVD detail — the highest-signal list there is. 'Recent' triages newly published CVEs. 'Search' finds CVEs mentioning a vendor or product.

## `keyword` (type: `string`):

Required for search mode. Matches the CVE description, e.g. 'fortinet', 'wordpress', 'apache', 'citrix'.

## `cvssSeverity` (type: `string`):

Optional. Applies to 'recent' and 'search' modes. Note that severity alone is a poor filter — that is what the EPSS threshold below is for.

## `minEpss` (type: `string`):

Optional but powerful. EPSS is the probability a CVE will be exploited within 30 days. 0.01 = top ~5% of all CVEs, 0.1 = genuinely likely. Rows with no EPSS score are excluded when this is set.

## `ransomwareOnly` (type: `boolean`):

Return only CVEs that CISA has confirmed are used in ransomware campaigns. The single most actionable filter in the dataset.

## `includeStandard` (type: `boolean`):

Uncheck to drop everything ranked STANDARD and keep only CVEs with a real exploitation signal.

## `daysBack` (type: `integer`):

For 'recent' mode: how far back to look. NVD allows a maximum window of 120 days.

## `publishedFrom` (type: `string`):

Optional explicit start date for 'recent' mode. Overrides 'days back'.

## `publishedTo` (type: `string`):

Optional explicit end date for 'recent' mode. The window must not exceed 120 days.

## `maxResults` (type: `integer`):

Optional cap. Rows are sorted most-urgent-first, so a small cap still returns the CVEs that matter most.

## Actor input object example

```json
{
  "mode": "kev",
  "keyword": "fortinet",
  "minEpss": "0.1",
  "ransomwareOnly": false,
  "includeStandard": true,
  "daysBack": 30,
  "maxResults": 100
}
```

# Actor output Schema

## `results` (type: `string`):

One row per CVE, most urgent first.

## `triage` (type: `string`):

Priority, exploit probability, KEV status and severity side by side.

## `runStats` (type: `string`):

Counts per priority band, plus the EPSS model date and KEV catalogue version used.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "mode": "kev",
    "daysBack": 30
};

// Run the Actor and wait for it to finish
const run = await client.actor("alinz/cve-triage").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "mode": "kev",
    "daysBack": 30,
}

# Run the Actor and wait for it to finish
run = client.actor("alinz/cve-triage").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "mode": "kev",
  "daysBack": 30
}' |
apify call alinz/cve-triage --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,alinz/cve-triage"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/iN2wJ5i2QED5IJo36/builds/vBPhrrFAVR1igbUlQ/openapi.json
