Skip to main content
Glama

CVE Tracker

CVE Tracker: Every public CVE in one place

Every public CVE in one place, free and open source. See how many vulnerabilities are published over time, browse the newest ones first, filter them down to what matters to you, and open any CVE for its scores, exploitation signals, affected products and links to the primary sources.

Live at trackcve.app, with its public API at api.trackcve.app.

Website CI License: MIT

CVE Tracker keeps its own copy of the public sources (the CVE List, NVD, CISA KEV, FIRST EPSS and the GitHub Advisory Database) and refreshes it every few minutes. It needs no paid API and no account, and runs on a single small server.

Website · API reference · MCP server · Architecture · Contributing · License

For terminal-first CVE tracking, try CVE Tracker CLI.

✨ Features

  • The whole CVE List: every published record (400,000+), refreshed every 10 minutes from the official CVE Program repository.

  • Timeline: CVEs per hour, day, week, month or year, depending on the period you look at, in three views:

    • New: counts stacked by severity.

    • Severity mix: each severity's share of a period.

    • Cumulative: the running total.

  • One filter for the chart and the table: full-text search (title, description, vendor, product) or a CVE id, a publication period (today, last 24 hours, this week … all time, or a custom range), severity, "known exploited only", a vendor and product (with suggestions, matching every affected product of a record) a package ecosystem (npm, PyPI, Maven, Go, NuGet, crates.io…, from reviewed GitHub advisories), a weakness (CWE) and the CNA that assigned it.

  • Take it with you: any filtered list downloads as CSV or JSON (up to 10,000 rows), and has its own Atom feed for a feed reader or a chat integration.

  • Recently added to KEV: what CISA added to its Known Exploited Vulnerabilities catalog, by day, whatever the CVE's age, with its own feed.

  • Statistics: severity, the most common weaknesses, vendors and CNAs of the last 7 days to 12 months.

  • Watchlist: watch any filter and see what each found in the last week, with all their feeds as one OPML file; kept in the browser, no account.

  • Badges: /badge/CVE-….svg shows a CVE's severity, score and KEV status in a README or a ticket.

  • Server-side sorting and paging: by publication date, CVE id, CVSS score, EPSS probability or the day it was added to KEV.

  • Shareable state: the filter, order, page and chart view all live in the URL. Copy it, bookmark it, send it; the browser's back button walks through your changes, and the way back from a CVE restores the list exactly as you left it.

  • CVE detail page:

    • description and dates

    • every CVSS score (assigner, CISA Vulnrichment, NVD) with vectors

    • EPSS with its history over the last month, and CISA SSVC

    • the CISA KEV entry, including known ransomware use

    • CWE, affected products and version ranges, affected packages from GitHub advisories

    • solutions, workarounds and references

    • links to CVE.org, NVD, OSV.dev, GitHub Advisories and CIRCL

  • Made to be found and cited: every CVE has its own server-rendered page with structured data and a share image; sitemaps for all of them, llms.txt, and a Markdown version of every CVE for AI agents (/cve/CVE-….md or Accept: text/markdown).

  • An MCP server for AI assistants: connect Claude, Cursor or any other client to https://api.trackcve.app/v1/mcp and let it search CVEs itself, with no key.

  • How it's built: docs/ARCHITECTURE.md, also on the site at trackcve.app/architecture.

  • Accessible: WCAG 2.2 AA, checked with axe-core; full keyboard use, screen reader announcements, light and dark themes, reduced motion, and a table view of every chart's numbers.

How it works

 CVE List (GitHub)  ─┐
 NVD API 2.0        ─┤  in-process sync  ┌───────────────┐  /v1/*   ┌──────────────────────┐
 CISA KEV (JSON)    ─┼─────────────────▶ │ backend       │ ───────▶ │ frontend             │
 FIRST EPSS (CSV)   ─┤                   │ Hono + SQLite │          │ TanStack Start (SSR) │
 GitHub advisories  ─┘                   │               │          │                      │
                                         └───────────────┘          └──────────────────────┘

Source

What it adds

How it is read

Default interval

CVE List (cvelistV5)

Every record, CNA scores, CISA Vulnrichment (ADP)

The whole repository as a tarball on the first run (~200 MB, about a minute), then deltaLog.json

10 min

NVD API 2.0

CVSS and CWE where the record has none of its own

Every CVE on the first run (~1 h without a key, minutes with a free one), then lastMod windows

60 min

CISA KEV

Known exploitation, ransomware use, remediation date

One JSON file from cisa.gov, or the same file from CISA's GitHub copy (cisagov/kev-data) when refused

6 h

FIRST EPSS

Probability of exploitation in the next 30 days

One gzipped CSV with every score; a CVE's history from FIRST's API when its page asks (cached)

6 h

GitHub Advisory Database

Affected packages and their ecosystems

The reviewed advisories (OSV format) from the repository's tarball (~150 MB, about 15 s)

12 h

The severity a CVE is listed with comes from the assigner's (CNA) CVSS score, else CISA's, else NVD's; a CVE nobody has scored yet is "Not scored".

Security and performance

  • Queries never block the server. Reads run in worker threads with read-only SQLite connections; a query still running after 3 s is stopped and its worker replaced, and past 200 waiting calls the API sheds load with 503 instead of piling up.

  • Fair use. Every caller gets 120 requests a minute; the frontend's own rendering is exempt through a shared token. Paging is capped at 10,000 results, and one- or two-letter prefixes are not expanded.

  • Answers are reused. The API keeps each answer for 30 seconds and drops them all when the sync changes the data; pages and answers carry s-maxage for a CDN.

  • Hardened pages. A strict Content-Security-Policy that allows inline scripts only by hash, frame-ancestors 'none', HSTS, nosniff, a strict referrer policy; external links open without passing the referrer.

  • The sync never loses changes. It only advances over runs the delta log really contains, retries records that could not be read or were still the cached previous version, and never re-downloads everything because of one bad answer.

  • Supply chain. Exact dependency versions, each at least 7 days old before pnpm installs it; only fixed, public sources are ever fetched.

Repository layout

apps/backend     HTTP API (Hono on Node 24), SQLite store with query worker threads, and the source sync
apps/frontend    Web app (TanStack Start, Router, Query, Table, Charts; Tailwind; Nitro)
packages/core    Shared API contract (zod/mini), typed API client, severity and time-bucket model
skills           A skill that tells an AI agent when and how to use the MCP server

Technology

Used for

TypeScript 7, Node 24, pnpm workspaces, Turborepo

One language end to end, exact dependency pins, 7-day release-age policy

Hono, node:sqlite (with FTS5), pino, zod

API, storage and full-text search with no native dependency, logging

React 19, TanStack Start / Router / Query / Table / Charts, Nitro

Server-rendered UI, URL-driven state, server-side table, charts

Tailwind CSS 4, Base UI, Lucide

Styling and accessible primitives

oxlint, oxfmt, Vitest

Lint, format and tests

Related MCP server: nist-nvd-mcp-server

🚀 Getting Started

You need Node 24.22.1 (see .node-version) and pnpm 12 (the exact version is pinned in package.json and fetched automatically).

git clone https://github.com/janszotkowski/cve-tracker.git
cd cve-tracker
pnpm install
cp apps/backend/.env.example apps/backend/.env
cp apps/frontend/.env.example apps/frontend/.env
pnpm dev

On the first start the backend downloads the CVE List into apps/backend/data/cve.db, which takes about a minute; KEV and EPSS follow within seconds. NVD then fills in scores in the background, so older CVEs show as "Not scored" for a while. A free NVD API key in NVD_API_KEY makes that take minutes instead of about an hour.

📖 Usage

The public API is read-only and works directly from a browser, script, or other HTTP client. For example:

curl https://api.trackcve.app/v1/summary
curl "https://api.trackcve.app/v1/cves?severity=CRITICAL"

Full reference with examples: trackcve.app/api (source: docs/API.md). OpenAPI 3.1: /v1/openapi.json.

The frontend uses a public, read-only JSON API that anyone may call, within a fair-use limit (120 requests a minute per address by default; RateLimit-* headers tell you where you stand, and a 429 carries Retry-After). Answers carry Cache-Control headers suitable for a CDN; please cache on your side too. Paging reaches the first 10,000 results of a filter; narrow it or change the order for the rest.

Endpoint

Returns

GET /v1/health

{ status, version }

GET /v1/summary

Headline counts and when each source was last read

GET /v1/cves

One page of CVEs for a filter

GET /v1/timeline

Matching CVEs per time bucket and severity, for the same filter (bucket width follows the period)

GET /v1/cves/:id

Everything known about one CVE, with links to its sources

GET /v1/cves/:id/epss

The CVE's EPSS day by day over the last month (from FIRST, cached)

GET /v1/export

Every CVE of a filter (up to 10,000), in the list's order: format=csv (default) or json

GET /v1/vendors

Vendors whose name contains q (the start of it for one or two letters), with CVE counts

GET /v1/products

The same for products, of one vendor when given

GET /v1/ecosystems

Package ecosystems with how many CVEs have a reviewed GitHub advisory in each

Filter parameters (shared by /v1/cves, /v1/timeline and /v1/export; the site's own address and its Atom feed, /feed.xml, take the same ones):

Parameter

Values

q

A CVE id or its start (CVE-2024-3), or words to search for

severity

Comma-separated: CRITICAL,HIGH,MEDIUM,LOW,NONE,UNKNOWN

kev

true for known exploited CVEs only

vendor, product

A vendor and/or product among the record's affected products, any case (vendor=Microsoft)

ecosystem

npm, PyPI, Maven, NuGet, Go, RubyGems, crates.io, Packagist, Pub, Hex, SwiftURL, GitHub Actions

range

all (default), today, 24h, week, 7d, month, 30d, 90d, year, 6m, 12m, custom

from, to

First and last day (YYYY-MM-DD, inclusive, UTC) of a custom range

sort, dir

published (default), updated, id, score, epss; desc (default) or asc

page, pageSize

Page number from 1; up to 100 per page (default 50)

The response shapes are defined once, as zod schemas, in packages/core/src/contract, and packages/core/src/client is a typed client for them.

MCP server

An AI assistant can use the same data over the Model Context Protocol. The server is free and read-only and needs no key. It has limits of its own and never uses more than one query worker, so agents cannot slow the site down.

claude mcp add --transport http cve-tracker https://api.trackcve.app/v1/mcp

Tool

Answers

search_cves

One page of CVEs for a filter, with the total

get_cve

One CVE in full

get_epss_history

A CVE's EPSS day by day over the last month

get_timeline

Matching CVEs per time bucket and severity

get_summary

Headline counts and when each source was last read

get_vendor

One vendor's or product's CVEs by severity and year, with its top weaknesses

get_weakness

One weakness's CVEs by severity and year, with the vendors it comes up for most

get_weekly_digest

One ISO week: the most severe, additions to KEV, top vendors and weaknesses

get_stats

Severity, top weaknesses, vendors and CNAs of a recent window

get_epss_movers

The CVEs whose EPSS rose the most

find_filter_values

How a vendor, product or CNA is spelled, and which filter values exist

Other clients and details: trackcve.app/mcp (source: docs/MCP.md).

⚙️ Configuration

The backend reads its settings from the environment once at start-up and refuses to start with a readable message when one is invalid. The full list, with defaults, is in apps/backend/src/config/env.ts.

Variable

Default

Meaning

PORT, HOST

4000, 0.0.0.0

Where the API listens

DATABASE_PATH

./data/cve.db

The SQLite file (created when missing)

CORS_ORIGINS

any localhost port (development)

Comma-separated origins of the frontend; required in production

NVD_API_KEY

none

Free NVD key: 50 requests per 30 s instead of 5

SYNC_ENABLED

true

Run the source sync in this process

SYNC_NVD_ENABLED

true

Enrich with NVD at all

SYNC_*_MINUTES

10 / 60 / 360 / 360 / 720

How often the CVE List, NVD, KEV, EPSS and GitHub advisories (GHSA) are read

LOG_LEVEL

info

pino log level

RATE_LIMIT_PER_MINUTE

120

Requests per caller per minute to /v1/* (health excepted)

CLIENT_IP_HEADER

connection address

Single-value header the proxy overwrites with the visitor's address (cf-connecting-ip, x-real-ip); x-forwarded-for is refused

INTERNAL_API_TOKEN

none

Shared with the frontend's server, so its rendering is limited per visitor (32+ chars)

RATE_LIMIT_RENDER_PER_MINUTE

600

Requests the frontend's rendering may make per minute for one visitor it names

RATE_LIMIT_EXPORT_PER_MINUTE

10

Exports (/v1/export) per caller per minute, on top of the general limit

MCP_ENABLED

true

Offer the MCP server at /v1/mcp

RATE_LIMIT_MCP_PER_MINUTE

60

Requests to /v1/mcp per caller per minute, on top of the general limit

RATE_LIMIT_MCP_TOTAL_PER_MINUTE

1200

Requests to /v1/mcp per minute for all callers together

QUERY_WORKERS, QUERY_TIMEOUT_MS

2, 3000

Query worker threads, and how long one query may run before it is stopped

RESPONSE_CACHE_SECONDS

30

How long an answer is reused; dropped whenever the sync changes the data

The frontend's settings are build-time (VITE_*, baked into the bundle) plus one runtime variable:

Variable

Meaning

VITE_API_URL

The API the browser calls (required for a build)

VITE_SITE_URL

The public origin of the site (canonical links)

VITE_ALLOW_INDEXING

true only for the production build; everything else answers noindex

API_INTERNAL_URL

Runtime, server only: an internal address of the API for server-side rendering

INTERNAL_API_TOKEN

Runtime, server only: the same token as the backend's

CLIENT_IP_HEADER

Runtime, server only: the header with the visitor's address behind a proxy

🚢 Deployment

The whole service is two small Node processes and one SQLite file of about 1.5 GB. Any server with 1–2 GB of RAM and a persistent disk is enough; a Hetzner CX22 (about €4 a month) runs it comfortably.

SITE_URL=https://cve.example.org \
API_URL=https://api.cve.example.org \
ALLOW_INDEXING=true \
NVD_API_KEY=your-key \
docker compose up -d --build

On your own server: DEPLOY.md is a step-by-step guide for a Hetzner server behind a Cloudflare Tunnel (about 7 € a month), with a script that sets everything up.

docker-compose.yml builds both images from the Dockerfile and keeps the database on a volume, so a new release reads only what changed since the last one. Put a CDN or reverse proxy (Cloudflare's free plan, Caddy) in front for TLS. Pages and API answers carry s-maxage, so a CDN that caches them (on Cloudflare, add a cache rule for HTML) answers most traffic; the API reuses its own answers for 30 seconds as well. Set INTERNAL_API_TOKEN (required by the Compose file) and, behind Cloudflare, CLIENT_IP_HEADER=cf-connecting-ip (both services read it).

Railway or Fly.io with a volume mounted at /data work too. Serverless platforms without a persistent disk do not fit: the database and the sync loop need one long-lived process.

📚 Documentation

  • API reference explains every public endpoint and filter with examples.

  • MCP server shows how to connect an AI assistant, and lists its tools.

  • Architecture describes the source sync, storage, backend, and frontend.

  • Deployment guide covers a production deployment behind a Cloudflare Tunnel.

  • Security policy explains how to report a vulnerability in CVE Tracker.

🛠️ Development

Use the commands below while developing or validating a change:

Command

What it does

pnpm dev

Backend and frontend with reload

pnpm build

Production build of every package

pnpm test

Unit and integration tests (Vitest)

pnpm e2e

Browser tests (Playwright) of production builds on a seeded database, desktop and phone, with an axe-core audit; run pnpm --filter @cve-tracker/e2e exec playwright install chromium once first

pnpm typecheck

TypeScript across the monorepo

pnpm lint

oxlint, warnings fail

pnpm format

oxfmt (use pnpm format:check to only check)

pnpm verify

Everything CI runs: lint, format check, typecheck, tests, build

🤝 Contributing

Contributions are welcome: bug reports, data issues, new chart views, new sources. Please read CONTRIBUTING.md first; everyone taking part follows the Code of Conduct. To report a security problem in CVE Tracker itself, see SECURITY.md.

🐛 Issues & Support

Open an issue for a bug, data issue, or feature request. For a security issue in CVE Tracker itself, follow the private reporting process in SECURITY.md.

📋 Code of Conduct

Everyone taking part in the project is expected to follow the Code of Conduct.

📄 License

CVE Tracker shows public data as published by its sources, without warranty of any kind. Always check the primary source before acting on it.

  • CVE® is a registered trademark of The MITRE Corporation. CVE records come from the CVE Program.

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

  • Known exploited vulnerabilities come from the CISA KEV catalog. cisa.gov refuses many data-centre addresses, so the sync falls back to CISA's own copy of the same file on GitHub (cisagov/kev-data).

  • EPSS scores come from FIRST: Jacobs, Romanosky, et al., Exploit Prediction Scoring System.

  • Affected packages come from the GitHub Advisory Database, licensed under CC-BY 4.0.

MIT © Jan Szotkowski. The data shown by the service stays under the terms of its respective sources.

👥 Authors & Contributors

Created and maintained by Jan Szotkowski. See the contributor graph for everyone who has helped improve CVE Tracker.

Related MCP Connectors

Related MCP Servers