# NVD CVE Monitor (new & modified CVEs, KEV flag) (`keepable_injera/nvd-cve-monitor`) Actor

Track new and modified CVEs from the NVD CVE API 2.0 by keyword, CPE, vendor and severity, flagged with the CISA KEV catalogue, with onlyNew change detection. Unofficial. This product uses the NVD API but is not endorsed or certified by the NVD.

- **URL**: https://apify.com/keepable_injera/nvd-cve-monitor.md
- **Developed by:** [Chee Chiaw Lim](https://apify.com/keepable_injera) (community)
- **Categories:** Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1.00 / 1,000 cve 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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## NVD CVE Monitor

### What it does

Fetch new or modified CVEs from the public NVD CVE API 2.0. Add CISA Known Exploited Vulnerabilities flags and detect changes between runs.

This product uses the NVD API but is not endorsed or certified by the NVD.

### Input examples

Fetch up to five recently modified Apache CVEs, including records emitted before.

```json
{ "mode": "modified", "lookbackHours": 24, "keywords": ["apache"], "maxItems": 5, "onlyNew": false }
```

Monitor recently published high or critical CVEs listed in KEV.

```json
{ "mode": "published", "lookbackHours": 168, "severities": ["HIGH", "CRITICAL"], "kevOnly": true, "onlyNew": true }
```

### Input fields

| Field | Default | Meaning |
| --- | --- | --- |
| `mode` | `modified` | `modified` uses lastModStartDate/lastModEndDate. `published` uses pubStartDate/pubEndDate. |
| `lookbackHours` | `24` | Window ending at run start, clamped to 1 through 2880 hours, or 120 days. Dates use ISO UTC with the Z offset. |
| `keywords` | `[]` | Each entry becomes one keywordSearch query. Empty means no keyword filter. |
| `cpeNames` | `[]` | Optional exact CPE names. Each is queried with every keyword. |
| `severities` | `[]` | Local filter on LOW, MEDIUM, HIGH, CRITICAL. Empty accepts all. |
| `vendors` | `[]` | Local case-insensitive match on CPE vendor components. Empty accepts all. |
| `kevOnly` | `false` | Emit only CVEs in the CISA KEV catalog. |
| `maxItems` | `200` | Maximum emitted CVEs, clamped to 1 through 10000. |
| `onlyNew` | `true` | Emit new and changed records. False also emits unchanged records. |
| `apiKey` | absent | Optional secret personal NVD key, sent in the apiKey header and never logged. |
| `stateStoreName` | `nvd-cve-monitor-state` | Named KV store for CVE history and KEV cache. |

CVSS selection prefers v3.1, then v3.0, then v4. Within each version it prefers a Primary metric. CVEs without metrics have null score and severity. Vendor and product lists come from configuration CPE criteria, including environmental criteria. References contain at most 20 distinct URLs. Keywords and CPE queries form a union; filters then apply locally. Duplicate CVE IDs emit once per run.

### Output sample

This is a synthetic fixture record, not a claim about a real vulnerability.

```json
{
  "cveId": "CVE-2026-10001",
  "published": "2026-10-19T01:00:00.000",
  "lastModified": "2026-10-20T01:00:00.000",
  "vulnStatus": "Analyzed",
  "description": "Fixture vulnerability in Apache HTTP Server.",
  "cvssVersion": "3.1",
  "cvssScore": 8.8,
  "severity": "HIGH",
  "cvssVector": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
  "cwes": ["CWE-79"],
  "vendors": ["apache"],
  "products": ["http_server"],
  "references": ["https://example.org/advisory"],
  "kev": true,
  "kevDateAdded": "2026-10-20",
  "kevDueDate": "2026-11-10",
  "kevRansomware": "Unknown",
  "nvdUrl": "https://nvd.nist.gov/vuln/detail/CVE-2026-10001",
  "changeType": "new",
  "changedFields": [],
  "checkedAt": "2026-10-20T12:00:00.000Z"
}
```

The default dataset holds CVEs and uncharged error rows. Errors contain `error` and `checkedAt`. The default KV store contains `RUN_SUMMARY` with timestamps, counts and `stoppedAtChargeLimit`. `counts.fetched` counts distinct CVEs that passed source filters and reached main, not every upstream response row.

### Change tracking

`CVES` in the named state store maps IDs to SHA-256 fingerprints and the tracked values. The stable JSON uses the fixed field order `lastModified`, `vulnStatus`, `cvssScore`, `severity`, `kev`. `changeType` is `new`, `changed`, or `unchanged`. `changedFields` names differing tracked fields and is empty for new records.

History is saved only after a successful dataset push. Charge-limited and failed pushes remain eligible. Pushes and KV writes are separate operations, so a crash between them can cause a duplicate on retry. Avoid concurrent runs sharing one state store. Use different names for independent histories. State grows with emitted CVE IDs.

The CISA catalog is fetched at most once per run and cached for 24 hours under `KEV`. A failed refresh stops the run rather than falsely clearing KEV flags. KEV changes are detected only for CVEs returned by the current NVD date window. This Actor does not rescan older CVEs outside that window.

### Pricing

The PPE event is `cve` at $0.001 per emitted CVE, or $1 per 1,000 CVEs, with no run fee. Errors and skipped CVEs are not charged. With `onlyNew` false, repeated unchanged CVEs are charged when emitted. Local runs do not bill PPE. Store pricing must be configured separately as described in `PUBLISHING.md`.

### Limits and terms

NVD requests start at least 6500 ms apart without a key, respecting the public five-requests-per-30-seconds limit. A personal API key changes that interval to 700 ms. Never share a key; use only your own. Schedule incremental modified-date runs no more often than once every two hours, following NVD guidance.

Requests use `politeFetch` with per-host throttling, HTTP 429 and 5xx retries, exponential backoff, Retry-After support and a 30-second request timeout. NVD pages request 2000 records. The Actor stops at `maxItems` or the PPE charge limit. Selective local filters may require scanning many pages. API availability and NVD analysis completeness affect results.

NVD data is public domain under Title 17. This Actor extracts source fields without rewriting CVE descriptions. See [TERMS.md](TERMS.md), [NVD terms](https://nvd.nist.gov/developers/terms-of-use), [NVD API documentation](https://nvd.nist.gov/developers/vulnerabilities), and the [CISA KEV catalog](https://www.cisa.gov/known-exploited-vulnerabilities-catalog). The terms review supplied with this repository is the basis for these notes.

This Actor is unofficial and is not affiliated with or endorsed by NVD, NIST, or CISA. It uses public documented APIs only, no logos, and no login. CVE and KEV flags are source data, not a complete security assessment.

### Local development

Node 20 or newer is required. Run offline tests with `npm test`. The sample INPUT is a live query limited to five CVEs. `npm start` normally accesses the public APIs.

Run the real Actor with stubbed HTTP and local storage without network access.

```sh
NODE_OPTIONS="--import=./scripts/offline-fetch.js" npm start
```

The preload accepts only the two source hosts and returns small realistic synthetic API fixtures. Inspect `storage/datasets/default/` and `storage/key_value_stores/default/RUN_SUMMARY.json`. Keep only the sample INPUT in version control. Tests use node:test, stub fetch and temporary local storage.

# Actor input Schema

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

Date window to query.

## `lookbackHours` (type: `integer`):

Hours before run start. Maximum 120 days.

## `keywords` (type: `array`):

Each keyword is a separate query. Empty means no keyword filter.

## `cpeNames` (type: `array`):

Optional exact CPE names. Each is queried with each keyword.

## `severities` (type: `array`):

Local severity filter. LOW, MEDIUM, HIGH, CRITICAL.

## `vendors` (type: `array`):

Local case-insensitive CPE vendor filter.

## `kevOnly` (type: `boolean`):

Emit only CVEs listed in CISA KEV.

## `maxItems` (type: `integer`):

Maximum CVE records emitted.

## `onlyNew` (type: `boolean`):

Emit only new or changed fingerprints.

## `apiKey` (type: `string`):

Optional personal NVD API key. Sent only in the apiKey header.

## `stateStoreName` (type: `string`):

Named KV store containing fingerprints and the 24-hour KEV cache.

## Actor input object example

```json
{
  "mode": "modified",
  "lookbackHours": 24,
  "keywords": [
    "apache"
  ],
  "cpeNames": [],
  "severities": [],
  "vendors": [],
  "kevOnly": false,
  "maxItems": 5,
  "onlyNew": true,
  "stateStoreName": "nvd-cve-monitor-state"
}
```

# Actor output Schema

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

No description

## `runSummary` (type: `string`):

No description

# 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 = {
    "keywords": [
        "apache"
    ],
    "maxItems": 5
};

// Run the Actor and wait for it to finish
const run = await client.actor("keepable_injera/nvd-cve-monitor").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 = {
    "keywords": ["apache"],
    "maxItems": 5,
}

# Run the Actor and wait for it to finish
run = client.actor("keepable_injera/nvd-cve-monitor").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 '{
  "keywords": [
    "apache"
  ],
  "maxItems": 5
}' |
apify call keepable_injera/nvd-cve-monitor --silent --output-dataset

```

## MCP server setup

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

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/uBR8Y95AvZC6Yvlgf/builds/Q1VkfmlhlH9jIqobl/openapi.json
