Back to glossary

GitHub Advisory Database (GHSA)

The GitHub Advisory Database is GitHub's open catalog of vulnerability and malware advisories for open source packages, keyed by GHSA IDs in OSV format.

Also known as GitHub Security Advisories, GitHub Security Advisory, GHSA ID, github/advisory-database, GitHub Advisory DB

The GitHub Advisory Database is GitHub's public catalog of security advisories for open source packages, also known as GHSA after its GitHub Security Advisory IDs. It merges NVD CVEs, maintainer-published advisories, and ecosystem databases, and GitHub curators map reviewed entries to exact package versions. npm audit, OSV.dev, and GitHub's own alerts all match against that mapping.

The mapping is the whole product. A scanner can match an advisory only if its affected field names an ecosystem, a package, and a version range. GitHub's curators fill that field during review. Unreviewed advisories are raw imports from the National Vulnerability Database, and in both months we sampled, every one had "affected": []. As of October 16, 2026, the github/advisory-database repository holds 389,825 advisories, and only 36,885 of them are GitHub-reviewed. That is 9.5%.

Our position: the GitHub Advisory Database is the best open dataset of known vulnerabilities in open source packages, and the GHSA ID has become the join key that tools use to talk about them. It is also a record of what someone already noticed. Malware advisories sit behind a non-default API filter and are absent from the git repository, and no advisory exists until after an attack is detected. Treat the database as the floor for vulnerability data, not as a malware defense.

What is the GitHub Advisory Database?

#

The GitHub Advisory Database is a set of JSON records in the Open Source Vulnerability (OSV) format, one per advisory. GitHub serves the same data three ways: the browsable site at github.com/advisories, the global advisories REST API, and the git repository, which is licensed CC-BY 4.0. GitHub's documentation defines three record types:

  • Reviewed advisories have been checked by GitHub's curation team and mapped to a package in one of 12 supported ecosystems: Composer, Erlang, GitHub Actions, Go, Maven, npm, NuGet, pip, Pub, RubyGems, Rust, and Swift. Only reviewed advisories trigger GitHub's vulnerability alerts.
  • Unreviewed advisories are published automatically from the NVD feed. GitHub does not alert on them, because nobody has validated them or tied them to a package.
  • Malware advisories are published automatically from the npm security team and the OpenSSF Malicious Packages repository. They list affected versions and no fixed version, because the only remedy is removal.

Reviewed advisories come from several inputs. Maintainers publish repository security advisories on their own GitHub projects. The rest are imported from the NVD, the npm Security Advisories Database, FriendsOfPHP, the Go vulnerability database, the Python Packaging Advisory Database, RubySec, and RustSec. Anyone can propose a correction: every advisory page has a "Suggest improvements" link that opens a pull request against the repository, and GitHub's curators merge or close it.

npm is the largest ecosystem in the reviewed set. By our count of the repository on October 16, 2026, 7,840 reviewed advisories affect npm packages, followed by Maven (7,182), PyPI (6,574), Packagist (6,571), and Go (5,001).

What is a GHSA ID?

#

A GHSA ID is the GitHub Advisory Database's identifier for one advisory, written GHSA-xxxx-xxxx-xxxx. Each x is drawn from the 20-character alphabet 23456789cfghjmpqrvwx, which omits 0, 1, and every vowel. The characters are random and lowercase, so a GHSA ID encodes no year, ecosystem, or sequence number. That leaves 20^12, about 4.1 quadrillion, possible IDs. All 389,825 IDs in the repository match the regular expression GitHub documents, GHSA(-[23456789cfghjmpqrvwx]{4}){3}.

A GHSA ID is not a CVE ID, and the two are not interchangeable. When a CVE exists, it appears in the record's aliases array. When no CVE exists, the GHSA ID is the only public identifier. GHSA-only advisories are increasingly common. Of the 11,621 reviewed advisories first published in 2026, 1,836 have no CVE alias.

This is the reviewed record for CVE-2023-48022, a remote code execution flaw in the Ray compute framework, trimmed to the fields scanners use:

JSON
{
  "schema_version": "1.4.0",
  "id": "GHSA-6wgj-66m2-xxp2",
  "published": "2023-11-28T09:30:26Z",
  "aliases": ["CVE-2023-48022"],
  "affected": [{
    "package": { "ecosystem": "PyPI", "name": "ray" },
    "ranges": [{
      "type": "ECOSYSTEM",
      "events": [{ "introduced": "0" }, { "last_affected": "2.49.2" }]
    }]
  }],
  "database_specific": {
    "cwe_ids": ["CWE-829", "CWE-918"],
    "severity": "CRITICAL",
    "github_reviewed": true,
    "github_reviewed_at": "2025-09-30T18:19:55Z",
    "nvd_published_at": "2023-11-28T08:15:06Z"
  }
}

Three fields carry the meaning. affected[].package is the ecosystem and name that a scanner compares against your lockfile. ranges[].events uses OSV's event model: introduced: "0" and last_affected: "2.49.2" mean every version up to and including 2.49.2. database_specific.github_reviewed_at records when a curator completed the mapping. In this record, that came 22 months after publication.

How does an advisory get into the GitHub Advisory Database?

#

An advisory enters the GitHub Advisory Database by one of three paths, and the path decides how quickly it becomes matchable.

The fast path is a repository security advisory. A maintainer drafts it privately in their own repository, can request a CVE from GitHub in the same workflow, and publishes it alongside the fix. The draft already names the package and the vulnerable versions, so GitHub's review is a check rather than a reconstruction. A 2026 study of the review pipeline measured the difference. For advisories published after June 2022, the median time to review was 0.45 days for repository advisories and 0.84 days for NVD-linked ones. Within five days, 95.4% of repository advisories were reviewed, against 78.2% of NVD-linked advisories.

The slow path is an NVD import. Every new CVE lands as an unreviewed advisory. A CVE record describes a product in prose and CPE strings, not as an ecosystem package name, so a person has to translate "Anyscale Ray 2.6.3 and 2.8.0" into PyPI/ray with a version range. Until someone does, the advisory has no affected entries and nothing can match it.

The third path is the automated malware feed, which bypasses review entirely and produces a different record type.

The figure above shows the same routing as this table. Each row is one way to read the database, and each column is one record type.

Access pathReviewedUnreviewedMalware
github.com/advisoriesYesYesYes, under the type:malware filter
REST API GET /advisoriesYes, the defaultOnly with type=unreviewedOnly with type=malware
git repository github/advisory-databaseYes, advisories/github-reviewedYes, advisories/unreviewedNo
npm registry bulk advisory endpoint (npm audit)Yes, npm onlyNever matches: no package fieldYes
OSV.devYes, imported from the git repositoryNoNo GHSA records; malware arrives separately as OpenSSF MAL- records

Our verdict: read the REST API with an explicit type=malware query, or use npm's endpoint, when you need malware coverage. Use OSV.dev when you need one feed across ecosystems that includes malware. Use the git repository for bulk analysis, knowing it contains no malware advisories at all.

Reviewed versus unreviewed advisories

#

An unreviewed advisory in the GitHub Advisory Database is invisible to any tool that matches on package names. That does not make the 352,940 unreviewed records a backlog of 352,940 open source bugs. Many CVEs describe software that no package manager installs. Of advisories first published in September 2026, 13,181 are still unreviewed and 947 are reviewed. Among those 13,181, 980 mention WordPress, which is not a supported ecosystem. Of the same 13,181, 3,194 reference at least one github.com URL, a crude signal that the affected code may live in a public repository.

The dangerous cases are CVEs that do describe a package. CVE-2023-48022 is one. The NVD published it on November 28, 2023, and GitHub imported it the same day as an unreviewed advisory. Ray's vendor disputed the report, attackers exploited the flaw anyway in the campaign Oligo named ShadowRay, and VulnCheck added it to its exploited-vulnerabilities list on August 24, 2024. The GHSA record still had no package mapping. On September 26, 2025, our researcher Jonathan Leitschuh opened pull request #6219 to add it:

Diff
-  "affected": [],
+  "affected": [
+    {
+      "package": {
+        "ecosystem": "PyPI",
+        "name": "ray"
+      },
+      "ranges": [
+        {
+          "type": "ECOSYSTEM",
+          "events": [
+            {
+              "introduced": "0"
+            }
+          ]
+        }
+      ]
+    }
+  ],

GitHub marked the advisory reviewed on September 30, 2025. For 22 months, an actively exploited remote code execution flaw in a project that had nearly 39,000 GitHub stars could not be matched against a requirements.txt by any tool reading the GitHub Advisory Database.

The ratio has improved slightly. A UC Irvine investigation found more than 213,000 unreviewed advisories in April 2024, with fewer than six reviewed per day, as our coverage of the OpenClaw advisory surge summarized. The 2026 study counted 8.2% reviewed out of 288,604 advisories as of August 21, 2025. Our count today is 9.5%.

The reviewed side is growing fast. The repository holds 11,621 reviewed advisories first published in 2026, more than three times the 3,691 from all of 2025. Much of that volume never touches the CVE system. OpenClaw, an AI agent project, published more than 200 GitHub security advisories in roughly three weeks, and 170 had no CVE at the time. When a CVE numbering authority offered to assign them, one maintainer replied: "GHSA's are fine at this stage, thanks." Tooling that only recognizes CVE IDs cannot see any of those advisories.

Are malware advisories in the GitHub Advisory Database?

#

Malware advisories are in the GitHub Advisory Database, but only in some views of it. GitHub's REST API documentation states the rule plainly: "By default, all responses will exclude advisories for malware, because malware are not standard vulnerabilities." The git repository goes further. Its tree contains only advisories/github-reviewed and advisories/unreviewed, and the malware advisories we checked are not in it.

OSV.dev inherits that gap and fills it from elsewhere. Its source configuration imports GHSA records only from the reviewed directory:

YAML
- name: 'ghsa'
  directory_path: 'advisories/github-reviewed'
  repo_url: 'https://github.com/github/advisory-database.git'
  db_prefix: ['GHSA-']

- name: 'malicious-packages'
  directory_path: 'osv'
  repo_url: 'https://github.com/ossf/malicious-packages.git'
  db_prefix: ['MAL-']

The September 2025 Qix maintainer compromise shows what this split looks like in practice. A phishing email gave an attacker the npm account behind chalk, debug, and 16 other packages, which together receive 2 to 3 billion downloads a week. All 18 malicious versions carried the same browser-side crypto-stealing payload. The GitHub Advisory Database recorded them as two different kinds of record:

Record typePackagesCVEIn the git repositoryPublished
Malware: "Malware in <package>"chalk, ansi-styles, strip-ansi, supports-color, wrap-ansi, ansi-regex, slice-ansi, chalk-template, has-ansi, supports-hyperlinksNoneNoSeptember 8, 2025 (chalk)
Reviewed vulnerability: "<package>@<version> contains malware after npm account takeover"debug, color-convert, error-ex, is-arrayish, simple-swizzle, color-name, color-string, backslashEight CVEs, CVE-2025-59140 through CVE-2025-59331YesSeptember 15, 2025

The second group exists because the packages' maintainers filed repository advisories a week later, each with a CVE. Ten of the 18 compromised packages had no CVE alias in any record we checked. A team that mirrors the git repository into its own scanner saw debug@4.4.2 flagged and chalk@5.6.1 clean.

The timeline in the figure, in text:

Time (UTC)Event
Sep 8, 13:12 to 13:16First wave of malicious versions published, including chalk@5.6.1 and debug@4.4.2
Sep 8, about two hours laterWe publish our analysis of the compromise
Sep 8npm removes the malicious versions over the course of the day
Sep 8, 17:07 to 17:24OpenSSF publishes MAL- records for the ten malware-type packages, each aliased to a GHSA malware ID; chalk's MAL-2025-46969 cites GitHub's malware feed as its source
Sep 10GHSA-2v46-p5h4-248w last updated
Sep 13The owner publishes clean patch versions to flush cached copies from private registries
Sep 15, 21:21 to 23:58Eight reviewed advisories with CVEs published from the maintainers' repository advisories, including GHSA-4x49-vf9v-38px for debug

The first advisory-derived record we can timestamp to the minute appeared just under four hours after the first malicious publish. That is fast for a public database and slow for an install. Every fresh install in that interval pulled the payload into node_modules, and into any browser bundle built from it, with no advisory to match. A malicious package delivered through a maintainer account takeover is only caught in time by analyzing the published code itself, before it is installed.

Tools that read the GitHub Advisory Database

#

Most tools consume the GitHub Advisory Database through one of the access paths in the table above. npm audit is the most direct example. It sends every package and version in your lockfile to the registry's bulk advisory endpoint, and the registry answers with GHSA records. We ran it on npm 10.9.4 against a lockfile containing minimist 1.2.5:

Bash
$ npm install minimist@1.2.5 --package-lock-only --ignore-scripts
$ npm audit --loglevel=http
npm http fetch POST 200 https://registry.npmjs.org/-/npm/v1/security/advisories/bulk 168ms
npm http fetch GET 200 https://registry.npmjs.org/minimist 61ms (cache revalidated)
# npm audit report

minimist  1.0.0 - 1.2.5
Severity: critical
Prototype Pollution in minimist - https://github.com/advisories/GHSA-xvch-5gv4-984h
fix available via `npm audit fix`
node_modules/minimist

1 critical severity vulnerability

The endpoint takes a JSON map of package names to versions, and you can query it directly. Unlike the REST API default, it returns malware advisories:

Bash
$ curl -s -X POST -H 'content-type: application/json' \
    https://registry.npmjs.org/-/npm/v1/security/advisories/bulk \
    -d '{"chalk":["5.6.1"]}' | jq .
{
  "chalk": [
    {
      "id": 1107375,
      "url": "https://github.com/advisories/GHSA-2v46-p5h4-248w",
      "title": "Malware in chalk",
      "severity": "critical",
      "vulnerable_versions": "=5.6.1",
      "cwe": [
        "CWE-506"
      ],
      "cvss": {
        "score": 0,
        "vectorString": null
      }
    }
  ]
}

The repository counts in this article are reproducible without API access. A blobless clone downloads only the file tree, which is enough to count records by type:

Bash
$ git clone --depth 1 --filter=blob:none --no-checkout \
    https://github.com/github/advisory-database
$ cd advisory-database
$ git ls-tree -r --name-only HEAD advisories | cut -d/ -f1-2 | sort | uniq -c
  36885 advisories/github-reviewed
 352940 advisories/unreviewed

npm audit answers one question: does the lockfile on disk today contain a version with an advisory? It cannot say whether you ran something earlier. During the axios compromise, packages executed through npx or installed globally never appeared in a project lockfile, and a clean check after the malicious version was removed did not prove a machine was unaffected.

The GHSA ID also serves as the shared key between tools. Socket Fix, for example, accepts GHSA IDs as its native input. It converts CVE IDs to GHSA IDs and resolves package URLs to the GHSA IDs that affect that package version before computing an upgrade.

Where the GitHub Advisory Database is fragile

#

The GitHub Advisory Database is only as accurate as the labels it inherits. Until 2025, OSV treated every CVE that the NVD marked "disputed" as withdrawn. OSV's disputed-CVE fix restored more than 500 advisories with a one-line change. GitHub's record for the Ray CVE had the same blind spot until the pull request above fixed it.

Severity is a judgment, and the judgment changes. Jerry Gamblin's Consensus Engine found 1,567 CVEs where GitHub and the NVD assigned different CVSS scores: the NVD scored higher 885 times and GitHub 682 times, as reported in our coverage of NIST's enrichment cutback. In the node-ip severity dispute of 2024, the maintainer archived his repository after a 9.8 critical advisory flooded his users with npm audit warnings. GitHub kept the advisory but lowered its severity to low. A CVSS score in a GHSA record says how bad a flaw could be. Whether your code calls the vulnerable function is a separate question, and it is the one that should drive triage.

The upstream feed is also shrinking. In April 2026, NIST stopped enriching most CVEs and now analyzes only those in CISA's Known Exploited Vulnerabilities catalog, federal software, and software designated critical. Every unreviewed GHSA record starts as an NVD import, so the database's slow path now begins with less data than it did a year ago. Withdrawals are part of the record too: 1,212 reviewed advisories in the repository are marked withdrawn.

GHSA records won because they are cheap to mint and carry the package mapping that CVE records lack. That makes the GitHub Advisory Database the right source of truth for known vulnerabilities in open source packages. The open problem is time. A security advisory begins at disclosure, and for a malicious publish the damage happens in the hours before anyone discloses anything.