Package lookups
Five routes that start from a package name rather than a CVE id or a query. They answer from different upstreams and are grouped here because a command-line tool holding a package name reaches for them in turn.
GET /api/v1/packages/index
GET /api/v1/search/package/:name
GET /api/v1/package/:name/history
GET /api/v1/package/:name/prs
GET /api/v1/graph/package/:name/vulnsFor a single package version by Package URL, see /purl/:purl on the SBOM analysis page. For OSV records alone, see OSV vulnerabilities; for nixpkgs-specific matching with confidence, CVE matching.
Every package this API can answer for
GET /api/v1/packages/indexA flat JSON array of package names with at least one advisory recorded, for clients that want to check membership locally rather than probe per package. There is no envelope. Cached for an hour.
["389-ds-base", "7zz", "a2ps", "accountsservice", "actual-server", "..."]Vulnerabilities affecting a package, from the general sources
GET /api/v1/search/package/:name?ecosystem=npm&version=4.17.20CVEs and advisories naming the package from the knowledge graph (if configured), OSV, GitHub Advisories and NVD, merged across the sources that answered and deduplicated by id. This route never queries nixpkgs security issues, the D1 search index, or EUVD: a package covered only by a nixpkgs security issue with no CVE/GHSA id is invisible here, even though the main search route would surface it. Written for command-line tools that hold a package name rather than a query; use the main search route for nixpkgs-specific coverage.
| Parameter | In | Required | Description |
|---|---|---|---|
name | path | Yes | Package name, scoped npm names included (@scope). At most 200 characters drawn from letters, digits, ., -, _ and /. |
ecosystem | query | No | OSV ecosystem (npm, PyPI, Go, ...). Scopes OSV's own query, and filters GitHub Advisories results to rows naming this ecosystem (GitHub's affects filter otherwise matches the bare name across every ecosystem it knows). NVD's keyword search has no ecosystem concept to scope by, so NVD is not queried at all when ecosystem is given, rather than mixing in results it cannot filter. |
version | query | No | Only OSV's own query is actually checked against this value. A GitHub Advisories or NVD row for the same package is included regardless of whether this version falls in its affected range; versionChecked on each row says which. |
{
"success": true,
"data": {
"package": "lodash",
"version": "",
"ecosystem": "npm",
"vulnerabilities": [
{
"cve_id": "CVE-2024-38986",
"title": "Prototype Pollution in 75lb deep-merge 1.1.1 allows attackers to execute arbitrary code ...",
"description": "...",
"severity": "critical",
"score": 9.8,
"published": "2024-07-30T20:15:03.990",
"source": "nvd",
"affected_versions": [],
"versionChecked": false
}
],
"count": 19,
"partial": false,
"failedSources": []
},
"timestamp": "2026-09-28T01:04:30.512Z"
}versionChecked is present on each row only when version was given in the request; true for an OSV row whose ranges were actually matched against it, false for a GitHub Advisories, NVD or knowledge-graph row merged in without that check. count is a floor when partial is true: the sources named in failedSources were not heard, so a short list is not a clean one. A name with characters package names never carry answers 400.
OSV history for a package
GET /api/v1/package/:name/history?ecosystem=npmEvery vulnerability OSV.dev lists for the package, newest first by published date. Follows OSV's own pagination rather than reading a single page: a package whose history spans more than one OSV page is counted in full, not undercounted at the first page's size.
{
"success": true,
"data": {
"package": "lodash",
"ecosystem": "npm",
"totalVulnerabilities": 12,
"truncated": false,
"vulnerabilities": [
{
"id": "GHSA-29mw-wpgm-hmr9",
"summary": "Regular Expression Denial of Service (ReDoS) in lodash",
"severity": "MODERATE",
"published": "2022-01-06T20:30:46Z",
"modified": "2024-04-15T18:12:09Z",
"affected": [{ "versions": [], "ranges": [] }]
}
]
},
"timestamp": "2026-09-28T01:05:52.318Z"
}truncated is true only when OSV still held a next-page token at the point the page bound stopped this read -- totalVulnerabilities is then a floor, not the real total. A bare name that exists in several ecosystems (lodash, requests) cannot be resolved by OSV and answers 400 asking for one. ecosystem reads all in the body when none was given.
Recent nixpkgs pull requests mentioning a package
GET /api/v1/package/:name/prsThe ten most recently updated nixpkgs pull requests whose text mentions the package, from GitHub search, cached for 30 minutes. A mention is a search hit and not a statement that the pull request changes the package.
{
"success": true,
"data": [
{
"number": 550095,
"title": "nixos/comfyui: add acceleration, models and extraPackages options",
"author": "knightfemale",
"state": "open",
"createdAt": "2026-08-07T06:00:41Z",
"url": "https://github.com/NixOS/nixpkgs/pull/550095",
"labels": ["6.topic: nixos", "8.has: documentation"]
}
],
"total": 214,
"timestamp": "2026-09-28T01:05:57.902Z"
}total is GitHub's count of matching pull requests, of which at most ten are returned. A GitHub failure answers 502 with data: null rather than an empty list, so an outage is never read as no pull requests.
Vulnerabilities for a Package, from OSV
Returns the vulnerabilities OSV.dev lists for a package in one ecosystem. The path keeps a /graph prefix because the package pages on cve.vulnpatch.dev already call it; the answer comes from OSV, and the body says so in source.
GET /api/v1/graph/package/:name/vulns?ecosystem=:ecosystemParameters
| Parameter | In | Required | Description |
|---|---|---|---|
name | path | Yes | Package name as the ecosystem spells it (e.g. lodash) |
ecosystem | query | Yes | OSV ecosystem (npm, PyPI, Go, crates, Debian, ...). OSV rejects a query without one, so the route answers 400 rather than sending it. |
Response
{
"success": true,
"data": {
"package": "lodash",
"ecosystem": "npm",
"source": "osv",
"vulnerabilities": [
{
"cveId": "CVE-2021-23337",
"advisoryId": "GHSA-35jh-r3h4-6jhm",
"cveIds": ["CVE-2021-23337", "CVE-2026-4800"],
"upstream": [],
"severity": "high",
"score": 7.2,
"published": "2021-05-06T16:05:51Z",
"description": "Command Injection in lodash"
}
],
"count": 1,
"truncated": false
},
"timestamp": "2026-09-28T00:12:41.020Z"
}truncated is true when OSV held more pages than this route reads. One row per OSV record. cveId is the CVE where OSV assigned one and the record's id otherwise; advisoryId is always the record's id, and cveIds lists every CVE it names. A record is left out only when every CVE it names is already on an earlier row, so a GHSA and a PYSEC for one CVE are one row, but an advisory that names a second CVE is kept. A downstream rebuild, such as Root's ROOT-OS-ALPINE-320-CVE-2024-47611, names its CVE only in upstream: it is not the CVE record, and cveId is its own id.
| Field | Description |
|---|---|
cveId | The CVE id where OSV has assigned one, otherwise the advisory id (GHSA-) |
severity | low, medium, high, critical or unknown, from the OSV severity block |
score | CVSS base score where OSV carries one, otherwise null |
published | OSV publication time |
timestamp | When this answer was produced. OSV is queried live; nothing is cached on this route |
Rows are ordered most recently published first. Fixed versions are not in this shape; the OSV Details route carries the affected ranges for one advisory.
Failures
| Status | code | Meaning |
|---|---|---|
400 | ECOSYSTEM_REQUIRED | No ecosystem given. links points at /osv, which asks every ecosystem |
500 | SOURCE_UNAVAILABLE | OSV did not answer. Not a statement that the package is clean; retry |
429 | Rate limited, as on every route |
An empty vulnerabilities list with success: true means OSV lists nothing for that package in that ecosystem. A failure is never rendered as an empty list.