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 everycveclaude mcp add --transport http everycve https://everycve.com/mcpcodex mcp add everycve --url https://everycve.com/mcpAny client that supports Streamable HTTP
https://everycve.com/mcpPaste this into your coding agent and it does the setup for you.
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.
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.
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/accounthas 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
detailisfull. check_package- What affects a package, and at a given version. Each match carries
evaluated,fixed_inand the sources’ rawclaims.truncatedmeans 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_truncatedorepss_truncatedmeans 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.
https://everycve.com/api/v1GET/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.
curl https://everycve.com/api/v1/entries/CVE-2022-22965{
"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.
curl https://everycve.com/api/v1/entries/batch \
-d '{"ids": ["CVE-2023-4863", "GHSA-j7hp-h8jx-5ppr"]}'{
"entries": [{ "id": "CVE-2023-4863", "status": "published" }]
}GET/entries
Search by keyword and filter. Results leave out each entry's heaviest fields. Pass next as offset to continue.
| Parameter | Meaning |
|---|---|
q | Keywords, or an exact ID. An exact ID returns the entry it names, and every other entry its advisory covers when it names several CVEs. The other parameters filter and page those entries like any search |
kev | In CISA KEV: true or false |
epss_gte | EPSS score at least, 0 to 1 |
cvss_gte | CVSS score at least, 0 to 10 |
cwe | A weakness, such as CWE-79 |
published_after | A date, as 2026-01-31 |
published_before | A date, as 2026-01-31 |
vendor | Vendor name, best effort |
product | Product name, best effort |
cpe | A CPE 2.3 string |
status | published, disputed, withdrawn or rejected |
limit | Up to 100, default 25 |
offset | Up to 5000 |
curl 'https://everycve.com/api/v1/entries?q=openssl&kev=true&epss_gte=0.5'{
"entries": [
{
"id": "CVE-2014-0160",
"status": "published",
"severity": {
"version": "3.1",
"score": 7.5,
"level": "high",
"from": "nvd"
},
"facts": {
"in_kev": true,
"public_exploit": true,
"fix_available": true
}
}
],
"next": 1
}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
affectedrecord for the package: itsrangesand any explicitversions. A range of typeUNPARSEDkeeps the source's own text inraw, with at most afixedevent. Read these by hand whenevaluatedisfalse. With a version, claims that ruled it out are left out. truncatedtruewhen the result hit its limits and some matches were left out.
curl 'https://everycve.com/api/v1/packages?ecosystem=npm&name=lodash&version=4.17.20'{
"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_truncatedtruewhen 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_truncatedtruewhen older scores exist beyond those listed. Absent otherwise.
curl https://everycve.com/api/v1/entries/CVE-2014-0160/history{
"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.
curl https://everycve.com/api/v1/entries/CVE-2021-44228/exploits{
"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.
curl 'https://everycve.com/api/v1/changes?since=2026-11-01T00:00:00Z'{
"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,errorornever. overduetruewhen the source has gone too long without a successful sync, or never had one.statusonly describes the last attempt, so a source can beokand overdue. Treat a source as healthy only whenstatusisokandoverdueisfalse.
curl https://everycve.com/api/v1/sources{
"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_daysdays. recent_trendupordownagainst the span before it, or empty when level.updated_at- When the counts were taken, or
nullbefore the first count.
curl https://everycve.com/api/v1/stats{
"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
#newor#kev, so one vulnerability can appear once for each. - Refresh
- Cached for up to 5 minutes.
https://everycve.com/feed.xml<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>GET/legal
The privacy policy and terms of service, the same text the website shows.
updated- The day the document last changed.
markdown- The document’s body as Markdown, without its title.
curl https://everycve.com/api/v1/legal{
"privacy": {
"updated": "2026-11-02",
"markdown": "This policy explains what \"Every CVE\" (the \"Service\") collects…"
},
"terms": {
"updated": "2026-11-01",
"markdown": "These terms cover \"Every CVE\" (the \"Service\")…"
}
}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.
| Field | Type | Meaning |
|---|---|---|
id | string | The primary ID, a CVE where one exists |
aliases | string[] | Other IDs for the same vulnerability |
status | string | published, disputed, withdrawn or rejected |
severity | object | The lead CVSS score. The CNA wins, then NVD, then others. from names the winner |
epss | object | Latest 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 |
facts | object | in_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 |
kev | object | The CISA KEV listing, when there is one |
exploits | object[] | 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_more | number | Exploit links left out of exploits. The exploits route lists them all. Absent when none are |
affected | object[] | 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 |
products | object[] | Vendor and product pairs |
references | object[] | Links about the vulnerability |
sources | object | Each source's own records, on single-entry reads |
also | string[] | 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
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.
curl -H "Authorization: Bearer everycve_…" \
https://everycve.com/api/v1/entries/CVE-2024-3094Errors
Errors share one shape. fields appears when specific parameters failed.
{
"error": { "code": "not_found", "message": "no entry for CVE-2099-1" }
}