Every CVE Search/ Get API key

Docs

One entry per vulnerability, merged from public sources. Connect an agent over MCP or call the REST API. Both read the same data.

On this page

Connect an agent

The MCP server speaks Streamable HTTP and needs no account, up to the rate limit. Connect your account for the higher one.

Works with most coding agents

npx add-mcp https://everycve.com/mcp --name everycve
claude mcp add --transport http everycve https://everycve.com/mcp
codex mcp add everycve --url https://everycve.com/mcp

Any client that supports Streamable HTTP

https://everycve.com/mcp

Paste this into your coding agent and it does the setup for you.

Setup prompt
Add the Every CVE MCP server to your MCP configuration.

Name: everycve
URL: https://everycve.com/mcp
Transport: Streamable HTTP
Authentication: none needed, under a lower rate limit

If I want the higher limit of an account, use https://everycve.com/mcp/account instead. It uses standard MCP OAuth, so I sign in from my browser when the client asks me to. If this client doesn't support MCP OAuth, keep the first URL and send my Every CVE API key in an "Authorization: Bearer" header.

Use your usual way of adding MCP servers. Then confirm it works by calling get_vulnerabilities with CVE-2014-0160, and tell me if I need to restart anything.

Connect your account

Without an account, MCP allows 120 requests a minute. An account allows 1000, shared by its API key and everything connected to it, so connecting more clients doesn’t add more.

Sign in from your client. Point a client that supports MCP authorization at this URL instead. It’s the same server, but it answers a client with no token with a 401, which is what makes clients open a browser. You sign in with GitHub or email and approve the client. It gets its own short-lived tokens, and never your API key. See and disconnect clients on your account. Replacing your API key disconnects them too.

Account URL
https://everycve.com/mcp/account

/mcp accepts these tokens too, but because it answers anonymous requests, clients have no reason to ask you to sign in there.

Or send your API key. For clients without MCP authorization, keep /mcp and add your API key as a header. X-API-Key also works.

Request header
Authorization: Bearer everycve_…

A key or token that isn’t valid gets a 401 rather than falling back to the anonymous limit. Its WWW-Authenticate header points to the metadata below, so a client can sign in again.

/.well-known/oauth-protected-resource/mcp
Protected resource metadata. /mcp/account has its own at the same path with that suffix.
/.well-known/oauth-authorization-server
Authorization server metadata: the authorization code flow with PKCE S256, for public clients.
Client identity
Client ID Metadata Documents, or Dynamic Client Registration at /oauth/register. Redirects must use HTTPS or a loopback address. Other schemes, such as a custom app scheme, are refused, as the MCP specification requires.
Tokens
Access tokens last an hour and only work at the MCP server, not the REST API. Refresh tokens rotate on each use, and last 30 days unused. Using an old one disconnects the client.

MCP tools

get_vulnerabilities
Look up to 100 entries by any ID. Compact unless detail is full.
check_package
What affects a package, and at a given version. Each match carries evaluated, fixed_in and the sources’ raw claims. truncated means matches were left out.
search_vulnerabilities
Find entries by keyword and filters. A query that is exactly an ID returns every entry that ID names, with the filters and paging applied.
list_changes
What changed since a time.
get_history
How one entry changed, with its EPSS trend. changes_truncated or epss_truncated means older rows were left out.

REST API

Every route is under the base URL below and returns JSON. Requests work without a key, up to the rate limit.

Base URL
https://everycve.com/api/v1

GET/entries/{id}

One entry by any ID it's known by: CVE, GHSA, OSV or EUVD. The response includes each source's own values under sources. See the entry object.

Request
curl https://everycve.com/api/v1/entries/CVE-2022-22965
Response, shortened
{
  "id": "CVE-2022-22965",
  "aliases": ["GHSA-36p3-wjmg-h94x"],
  "status": "published",
  "title": "Spring Framework JDK 9+ Remote Code Execution Vulnerability",
  "severity": {
    "version": "3.1",
    "score": 9.8,
    "vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
    "level": "critical",
    "assessor": "primary",
    "from": "nvd"
  },
  "epss": {
    "day": "2026-11-01",
    "score": 0.99638,
    "percentile": 0.9995,
    "model": "v2026.06.15"
  },
  "facts": {
    "in_kev": true,
    "public_exploit": true,
    "fix_available": true
  },
  "cwes": ["CWE-94"],
  "published": "2022-04-01T22:17:30Z",
  "exploits": [
    {
      "source": "metasploit",
      "id": "exploit/multi/http/spring_framework_rce_spring4shell",
      "type": "exploit",
      "date": "2022-03-31",
      "url": "https://www.rapid7.com/db/modules/exploit/multi/http/spring_framework_rce_spring4shell"
    }
  ],
  "affected": [
    {
      "source": "ghsa",
      "ecosystem": "Maven",
      "package": "org.springframework:spring-beans",
      "ranges": [
        {
          "type": "ECOSYSTEM",
          "events": [
            { "introduced": "5.3.0" },
            { "fixed": "5.3.18" }
          ]
        }
      ]
    }
  ]
}

POST/entries/batch

Up to 100 entries in one request. An ID with no entry is left out of the response.

Request
curl https://everycve.com/api/v1/entries/batch \
  -d '{"ids": ["CVE-2023-4863", "GHSA-j7hp-h8jx-5ppr"]}'
Response, shortened
{
  "entries": [{ "id": "CVE-2023-4863", "status": "published" }]
}

GET/packages

What affects a package. Pass ecosystem and name, and optionally version to keep only what affects that version. Withdrawn and rejected entries are left out.

With a version, a match is left out only when every source's claim rules that version out. If any claim says it is affected, affected is true. Otherwise a claim that couldn't be compared, such as git commits or a range the source wrote in a form we can't read, leaves evaluated false and affected null, which means the version may or may not be affected. It never means safe.

fixed_in
Versions the sources report as fixing it. A fix beside an unreadable range is the source's own claim.
claims
Each source's raw affected record for the package: its ranges and any explicit versions. A range of type UNPARSED keeps the source's own text in raw, with at most a fixed event. Read these by hand when evaluated is false. With a version, claims that ruled it out are left out.
truncated
true when the result hit its limits and some matches were left out.
Request
curl 'https://everycve.com/api/v1/packages?ecosystem=npm&name=lodash&version=4.17.20'
Response, shortened
{
  "ecosystem": "npm",
  "name": "lodash",
  "version": "4.17.20",
  "matches": [
    {
      "entry": { "id": "CVE-2021-23337", "status": "published" },
      "affected": true,
      "evaluated": true,
      "fixed_in": ["4.17.21"],
      "claims": [
        {
          "source": "ghsa",
          "ecosystem": "npm",
          "package": "lodash",
          "ranges": [
            {
              "type": "ECOSYSTEM",
              "events": [{ "introduced": "0" }, { "fixed": "4.17.21" }]
            }
          ]
        }
      ]
    }
  ]
}

GET/entries/{id}/history

How one entry changed since Every CVE first saw it, plus its daily EPSS scores, newest first. Each list is capped at its newest rows: 500 changes and 3000 days of scores.

changes_truncated
true when older changes exist beyond those listed. Absent otherwise.
model
The EPSS model that made each score. Scores jump when the model changes, so compare scores only within one model.
epss_truncated
true when older scores exist beyond those listed. Absent otherwise.
Request
curl https://everycve.com/api/v1/entries/CVE-2014-0160/history
Response, shortened
{
  "id": "CVE-2014-0160",
  "changes": [
    {
      "entry": "CVE-2014-0160",
      "seq": 36,
      "at": "2026-11-01T18:40:13Z",
      "sources": ["pocgithub"],
      "fields": ["exploits"]
    }
  ],
  "epss": [
    { "day": "2026-11-01", "score": 0.99999, "percentile": 0.99996, "model": "v2026.06.15" }
  ]
}

GET/entries/{id}/exploits

Every exploit link for one entry. An entry keeps at most 25 links from each source, and exploits_more on the entry counts the rest. This lists them all, in the entry's order: links to public code first, then the oldest.

Request
curl https://everycve.com/api/v1/entries/CVE-2021-44228/exploits
Response, shortened
{
  "exploits": [
    {
      "source": "pocgithub",
      "id": "tangxiaofeng7/CVE-2021-44228-Apache-Log4j-Rce",
      "title": "tangxiaofeng7/CVE-2021-44228-Apache-Log4j-Rce",
      "date": "2021-12-09",
      "url": "https://github.com/tangxiaofeng7/CVE-2021-44228-Apache-Log4j-Rce"
    }
  ]
}

GET/changes

Everything that changed since a time. Pass since and optionally limit, then pass next as after to continue.

Request
curl 'https://everycve.com/api/v1/changes?since=2026-11-01T00:00:00Z'
Response, shortened
{
  "changes": [
    {
      "entry": "CVE-2014-0160",
      "seq": 1,
      "at": "2026-11-01T18:40:13Z",
      "sources": ["cve"],
      "fields": ["created"]
    }
  ],
  "next": 1
}

GET/sources

Each source's sync state and license. The sources page shows the same data.

status
How the last attempt went: ok, error or never.
overdue
true when the source has gone too long without a successful sync, or never had one. status only describes the last attempt, so a source can be ok and overdue. Treat a source as healthy only when status is ok and overdue is false.
Request
curl https://everycve.com/api/v1/sources
Response, shortened
{
  "sources": [
    {
      "name": "cve",
      "title": "CVE List",
      "kind": "records",
      "about": "The official CVE records, and the starting point for most entries.",
      "homepage": "https://www.cve.org",
      "license": "CVE Terms of Use",
      "interval": "30m",
      "last_success": "2026-11-01T18:40:13Z",
      "status": "ok",
      "records": 312408,
      "overdue": false
    }
  ]
}

GET/stats

The headline counts. They’re saved after each ingest that changes an entry, and one row a day is kept, so this reads them rather than counting anything.

known_cves
Entries with a CVE ID, leaving out rejected and withdrawn ones.
exploited
Entries in CISA KEV.
recent
Entries published in the last recent_days days.
recent_trend
up or down against the span before it, or empty when level.
updated_at
When the counts were taken, or null before the first count.
Request
curl https://everycve.com/api/v1/stats
Response
{
  "known_cves": 312408,
  "exploited": 1484,
  "recent": 4120,
  "recent_days": 30,
  "recent_trend": "up",
  "updated_at": "2026-11-01T18:00:00Z"
}

GET/feed.xml

The 100 newest items for a feed reader: entries as they’re first seen, and entries as they’re added to CISA KEV. It needs no key.

The feed sits at the site’s root, not under the API’s base URL.

Format
Atom 1.0, served as application/atom+xml. This is the only feed format for now. For JSON, use recent changes.
Item IDs
The entry’s URL, ending in #new or #kev, so one vulnerability can appear once for each.
Refresh
Cached for up to 5 minutes.
Feed URL
https://everycve.com/feed.xml
Response, shortened
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Every CVE: new vulnerabilities and KEV additions</title>
  <id>https://everycve.com/feed.xml</id>
  <updated>2026-11-02T03:46:46Z</updated>
  <entry>
    <title>CVE-2023-4863 added to CISA KEV: Google Chromium WebP Heap-Based Buffer Overflow Vulnerability</title>
    <id>https://everycve.com/CVE-2023-4863#kev</id>
    <updated>2023-09-13T00:00:00Z</updated>
    <link href="https://everycve.com/CVE-2023-4863"/>
  </entry>
</feed>

The entry object

An entry is one vulnerability, merged from every source that mentions it. Top-level fields hold the value Every CVE chose, and sources keeps what each source said. An advisory covering several CVEs belongs to each CVE's entry and is listed in also.

Fields of an entry
FieldTypeMeaning
idstringThe primary ID, a CVE where one exists
aliasesstring[]Other IDs for the same vulnerability
statusstringpublished, disputed, withdrawn or rejected
severityobjectThe lead CVSS score. The CNA wins, then NVD, then others. from names the winner
epssobjectLatest chance of exploitation in the next 30 days. model names the EPSS model that made the score, and scores from different models aren't comparable. The first model is v1
factsobjectin_kev, public_exploit and fix_available. public_exploit is true only when a source links to code that exploits the vulnerability. A KEV listing alone doesn't set it, nor does a detection template such as Nuclei's, nor a Metasploit module that is not an exploit, such as an auxiliary scanner
kevobjectThe CISA KEV listing, when there is one
exploitsobject[]Links to public exploit code, and to detection templates and scanners that only check for the flaw. Every CVE stores no exploit code. At most 25 per source, links to public code and the oldest first
exploits_morenumberExploit links left out of exploits. The exploits route lists them all. Absent when none are
affectedobject[]Packages, version ranges and explicit versions, by source. A range of type UNPARSED keeps the source's own text in raw and can only mean unknown
productsobject[]Vendor and product pairs
referencesobject[]Links about the vulnerability
sourcesobjectEach source's own records, on single-entry reads
alsostring[]Other entries an ID resolved to

The public GET /api/v1/config endpoint reports the current rate limits and request caps. These pages use the same values.

Rate limits and keys

120requests a minute with no key
1000requests a minute with an API key

Send a key as a bearer token. The limit belongs to the account, so replacing a key or connecting another client doesn’t start a new count. Every response reports your remaining requests in X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset.

Request
curl -H "Authorization: Bearer everycve_…" \
  https://everycve.com/api/v1/entries/CVE-2024-3094

Errors

Errors share one shape. fields appears when specific parameters failed.

404 response
{
  "error": { "code": "not_found", "message": "no entry for CVE-2099-1" }
}
MoveEnter Open