Skip to content

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/vulns

For 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/index

A 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.

json
["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.20

CVEs 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.

ParameterInRequiredDescription
namepathYesPackage name, scoped npm names included (@scope/name). At most 200 characters drawn from letters, digits, ., -, _ and /.
ecosystemqueryNoOSV 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.
versionqueryNoOnly 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.
json
{
  "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=npm

Every 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.

json
{
  "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/prs

The 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.

json
{
  "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=:ecosystem

Parameters ​

ParameterInRequiredDescription
namepathYesPackage name as the ecosystem spells it (e.g. lodash)
ecosystemqueryYesOSV ecosystem (npm, PyPI, Go, crates.io, Debian, ...). OSV rejects a query without one, so the route answers 400 rather than sending it.

Response ​

json
{
  "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.

FieldDescription
cveIdThe CVE id where OSV has assigned one, otherwise the advisory id (GHSA-...)
severitylow, medium, high, critical or unknown, from the OSV severity block
scoreCVSS base score where OSV carries one, otherwise null
publishedOSV publication time
timestampWhen 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 ​

StatuscodeMeaning
400ECOSYSTEM_REQUIREDNo ecosystem given. links.osv points at /osv/:package, which asks every ecosystem
500SOURCE_UNAVAILABLEOSV did not answer. Not a statement that the package is clean; retry
429Rate 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.