API Overview
The Vulnpatch API provides programmatic access to vulnerability data aggregated from multiple sources.
Base URL
https://api.vulnpatch.dev/api/v1/Endpoints Summary
Every route below is served today and described in openapi.json, except where a row says otherwise. A test in the repository checks that the router, the spec and these pages name the same routes, so a route missing from this page is a defect rather than an omission.
Nixpkgs-Specific Endpoints
These endpoints return data only from nixpkgs security issues and the nixpkgs repository:
| Method | Endpoint | Description |
|---|---|---|
GET | /nix/stats | Counts of open nixpkgs security issues |
GET | /nix/cves | One page of the newest open nixpkgs security issues filed by the automated matcher, with linked PRs; partial is always true. Use /issues for every issue |
GET | /nix/channels | Where each NixOS channel stands, as NixOS's monitoring reports it; inferred only when no reading is held, and the body says which |
GET | /nix/ahead | New CVEs mapped to nixpkgs attributes as they arrive, with each channel's version against the affected ranges and when the security tracker filed |
GET | /nix/channels/history?channel= | Every observed change to one channel's revision or status, paged |
GET | /nix/repology/:package | The versions each nixpkgs channel carries, from Repology |
GET | /nix/hydra/:package | Latest Hydra builds of a package, per platform |
GET | /nix/pr/:number/backports | Whether a PR merged and which release branches carry a backport |
GET | /nix/stable/:series/containment/:sha | When a commit reached a stable channel release |
GET | /cve/:id/nix/channels | Fix status of a CVE per NixOS channel |
GET | /cve/:id/fix-timing?commit= | When a named fix commit reached each stable channel |
GET | /issues | List nixpkgs security issues (severity-enriched, with difficulty estimates) |
GET | /issues/:id | Get a specific nixpkgs security issue by number |
GET | /package/:name/prs | Recent nixpkgs pull requests mentioning a package |
GET | /sources | List available data sources |
Multi-Ecosystem Endpoints
These endpoints aggregate data from OSV.dev across 38+ ecosystems (npm, PyPI, Debian, etc.):
| Method | Endpoint | Description |
|---|---|---|
GET | /stats | Get aggregate statistics across all sources |
GET | /ecosystem-stats | Get aggregate ecosystem vulnerability counts |
GET | /ecosystem-severity/:ecosystem | Severity breakdown for one ecosystem |
GET | /recent-advisories | Get advisories published in last 12 hours |
GET | /osv/:package | Get vulnerabilities from OSV.dev |
GET | /vulns/:package | Get CVE matches with confidence scores |
GET | /osv-details/:id | Get detailed vulnerability information |
GET | /packages/index | Every package name with at least one advisory recorded |
GET | /search/package/:name | Vulnerabilities affecting a package, across sources |
GET | /package/:name/history | Every OSV vulnerability for a package, newest first |
CVE Endpoints
Direct CVE lookup from the official MITRE CVE List V5:
| Method | Endpoint | Description |
|---|---|---|
GET | /cve/:id | Get CVE details by ID (includes EPSS + KEV + data quality score inline) |
GET | /cve/:id/dossier | Agent-readable CVE dossier with provenance, quality gaps, ingest hints, and links back to cve.vulnpatch.dev |
GET | /cve/:id/verify | Re-read the record upstream, uncached, immediately before acting |
GET | /cve/:id/provenance | What each upstream source said about the CVE, and when it changed |
GET | /cve/:id/osv | The nixpkgs mapping as an OSV record |
GET | /aliases/:id | Any advisory id (GHSA, RUSTSEC, DSA, ...) to the CVEs it names |
GET | /relations/:id | The relationship graph around a CVE, advisory, package or weakness, each edge with its source |
POST | /cve/batch | Bulk lookup up to 50 CVEs |
POST | /cve/status | Status badges for a list of CVEs |
GET | /cve/:id/history | Get CVE change history |
GET | /cve/:id/at/:date | Query CVE state at specific date |
GET | /search?q=term&sort=date | Full-text search across CVEs (sort: date/severity) |
GET | /mitre/recent?limit=50 | Latest CVEs from MITRE delta feed (~24h ahead of NVD) |
Exploitability Intelligence
| Method | Endpoint | Description |
|---|---|---|
GET | /exploitability | EPSS scores + CISA KEV status for tracked CVEs |
GET | /kev/recent | The latest additions to the CISA KEV catalogue |
GET | /newly-actionable | CVEs whose EPSS score recently crossed the threshold |
GET | /cve/:id/lifecycle | Full vulnerability lifecycle timeline (disclosure to patch) |
GET | /cve/:id/exploit-signals | Weaponization signals (PoC repos, Nuclei, ExploitDB) |
GET | /cve/:id/ai-assessment | AI-generated plain-English impact assessment |
GET | /fix-etas | Fix ETA predictions per CVE |
GET | /rebuild-impact | Package rebuild impact analysis |
GET | /rebuild-impact/:name | Single package rebuild impact |
Analytics Endpoints
| Method | Endpoint | Description |
|---|---|---|
GET | /trending | Recently updated vulnerabilities |
GET | /analytics | Monthly CVE aggregates by severity, source and ecosystem |
GET | /severity-breakdown | Vulnerabilities by severity level |
GET | /fix-rate | Fix availability statistics |
GET | /package-health | Package maintenance health scores |
GET | /package-health/:name | Health score for one package |
GET | /analytics/time-to-fix | Historical time-to-fix benchmarks |
GET | /data-quality/stats | CVE data quality score distribution |
GitHub Security Advisories
| Method | Endpoint | Description |
|---|---|---|
GET | /ghsa | Recent GitHub Security Advisories, read with the server's own credential; 503 if none is configured |
Weekly Digest by Email
| Method | Endpoint | Description |
|---|---|---|
POST | /notify/subscribe | Follow CVEs and packages; a confirmation email is sent first |
POST | /notify/confirm/:token | Open the confirmation link |
GET | /notify/subscription/:token | What an address follows |
POST | /notify/unsubscribe/:token | Unsubscribe in one click (also the RFC 8058 target) |
POST | /notify/resubscribe/:token | Undo an unsubscribe, within 30 days |
POST | /notify/follows/:token | Replace what is followed |
POST | /notify/delete/:token | Delete everything held for the address |
Remediation Planning
| Method | Endpoint | Description |
|---|---|---|
POST | /remediation/plan | Generate minimal upgrade plan to fix CVEs |
GET | /verify-fix?url=&cves= | Whether a GitHub release or commit page names the CVE ids given |
SBOM & PURL
| Method | Endpoint | Description |
|---|---|---|
GET | /purl/:purl | PURL vulnerability lookup |
POST | /sbom/scan | Analyze an SBOM, no credential, 100 components |
POST | /sbom | The same operation at the same limits |
POST | /sbom/time-travel | Analyze SBOM exposure at a past date |
GET | /sbom/formats | Supported SBOM formats, PURL types and the enforced limits |
cve.vulnpatch.dev accepts a CycloneDX or SPDX SBOM as JSON and sends it to /sbom; the vulnerability report downloads as JSON. The site does not convert lockfiles. Generate the SBOM with your ecosystem's tooling first. A flake.lock is not supported: it pins a nixpkgs revision, not a package list, and which packages that revision carries is not yet indexed.
Source hashes
| Method | Endpoint | Description |
|---|---|---|
POST | /prefetch/:operation | Nix source and Go vendor hashes without a local Nix; see Source hashes |
Feeds
| Method | Endpoint | Description |
|---|---|---|
GET | /feed/rss | RSS feed of recent advisories |
GET | /feed/atom | Atom feed of recent advisories |
GET | /feed/osv/nixpkgs | The nixpkgs mapping as a bulk OSV feed |
/feed/rss and /feed/atom also answer at the host root, without /api/v1.
Knowledge Graph
Relationship questions are answered by Relations, /relations/:id above, from the search index and the dossier. The older Neo4j backend is not deployed: one route under /graph answers, from OSV; the rest return 503 with code: "GRAPH_UNAVAILABLE". See Knowledge Graph.
| Method | Endpoint | Description |
|---|---|---|
GET | /graph/package/:name/vulns?ecosystem= | CVEs affecting a package in one ecosystem, from OSV |
Service and Utility Endpoints
| Method | Endpoint | Description |
|---|---|---|
GET | /status | Whether the answer you are about to get can be trusted |
GET | /freshness | Measured ingest latency per source |
GET | /nvd/status | Progress of the NVD backfill and sync |
GET | /health | Health check |
GET | /version | API version info |
GET | /openapi.json | OpenAPI specification |
GET | /agent-manifest | The agent manifest; also at /.well-known/vulnpatch-agent.json |
/health, /version and /openapi.json also answer at the host root. The API host serves /llms.txt and /.well-known/security.txt as well.
Dashboard routes
POST /access-request, GET /access-request/:username, POST /pr/validate and POST /pr/fix exist for the private-beta dashboard, require the caller's GitHub token and are deliberately outside the public contract and the spec. POST /pr/signature is retired and answers 410. See Dashboard routes.
Common Parameters
Query Parameters
| Parameter | Type | Description |
|---|---|---|
ecosystem | string | Filter by ecosystem (e.g., npm, PyPI, Debian) |
version | string | Filter by package version |
Headers
| Header | Description |
|---|---|
Accept | Always returns application/json |
Response Format
Success Response
{
"success": true,
"data": {
// Endpoint-specific data
},
"timestamp": "2024-01-15T12:00:00.000Z"
}A few routes answer without the envelope, and their pages say so: /nix/channels, /nix/stable/:series/containment/:sha, /mitre/recent, /packages/index, /cve/:id/osv, /feed/osv/nixpkgs, /agent-manifest and the two XML feeds.
Error Response
{
"success": false,
"error": "Error message describing what went wrong"
}HTTP Status Codes
| Code | Description |
|---|---|
200 | Success (may include a placeholder when a CVE is allocated but not yet published; see below) |
400 | Bad request (invalid parameters) |
404 | Resource not found; for CVE endpoints, includes a stable code field. An unknown path answers JSON naming the spec |
405 | The path exists and does not take that method; Allow names the ones it does |
429 | Rate limit exceeded |
500 | Internal server error |
502 | An upstream this answer depends on could not be read |
503 | This service cannot answer yet: a feed not built, an index unreadable, a backend not deployed |
CVE endpoints: status contract
GET /api/v1/cve/:id and GET /api/v1/cve/:id/dossier share the same availability contract:
- Published:
200with full data. - Allocated but not yet enriched (the id is in the MITRE delta feed):
200with a minimal record. Lookup setsstatus.type = "UNPUBLISHED"; dossier setscanonical.availability = "awaiting_ingest"and theX-Dossier-Availabilityresponse header. - Reserved / Rejected / Withdrawn (MITRE acknowledges the id with that state):
200. The dossier'scanonical.availabilitycarries the exact state. - Unknown (no authority has allocated the id):
404with a structured body:
{
"success": false,
"error": "not_found",
"code": "CVE_UNKNOWN",
"hint": "No authority has allocated CVE-9999-99999. Verify the ID follows the CVE-YYYY-NNNNN+ format and check for typos."
}Clients should branch on code, not the free-text error message.
CORS
The API supports CORS for browser-based applications. All origins are allowed for read-only endpoints.
Caching
Responses include cache headers:
| Header | Description |
|---|---|
X-Cache | HIT if served from cache, MISS otherwise |
Cache-Control | Browser caching directives |
Rate Limiting
One Cloudflare edge rule is enforced: 2 requests per 10 seconds per address on the SBOM analysis paths and /cve/:id/ai-assessment. Every other route carries advisory X-RateLimit-* headers from a per-instance counter that is not an account-wide budget. There are no tiers and no credential raises a limit. See Rate Limits for the headers, the 429 bodies and how to behave around them.
OpenAPI Specification
The full API specification is available at:
https://api.vulnpatch.dev/openapi.jsonUse this to auto-generate clients in your language of choice with tools like OpenAPI Generator.
SDKs & Libraries
Currently, there are no official SDKs. The API is designed to be easily consumed with standard HTTP clients:
curl https://api.vulnpatch.dev/api/v1/statsconst response = await fetch('https://api.vulnpatch.dev/api/v1/stats');
const data = await response.json();import requests
response = requests.get('https://api.vulnpatch.dev/api/v1/stats')
data = response.json()