Skip to content

Allow a CVE to be linked to multiple GHSAs (or expose CVE relationships in structured data) so reviewed advisories don't lose their CVE #10224

Open

Description

@yusuke-koyoshi

Summary

A CVE can currently be attached to only one GHSA in the database backend. When the same vulnerability exists as more than one GHSA, only one of them can carry the CVE alias. The others end up with no CVE alias, and the relationship exists only as a reference URL or in free text, or not at all.

This makes it hard for consumers to join GHSA data with CVE-keyed sources such as CISA KEV, EPSS, NVD, and PoC/exploit databases.

Example 1: downstream advisory (Next.js)

  • CVE-2025-55182 is attached to GHSA-fv66-9v8q-g76r (React).
  • GHSA-9qr9-h5gf-34mp (Next.js) originally had CVE-2025-66478, which was rejected in accordance with CVE CNA rule 4.1.12. That rule says a downstream product advisory SHOULD reference the CVE ID of the vulnerable library.
  • However, CVE-2025-55182 cannot be added as an alias to GHSA-9qr9-h5gf-34mp because it is already attached to GHSA-fv66-9v8q-g76r. The NVD URL was added to references instead.
  • NVD lists Next.js CPEs under CVE-2025-55182, so NVD and GHSA now disagree on which products are associated with that CVE in structured form.

Discussion: #6496, #6521

Example 2: reviewed and unreviewed duplicates (renovate)

  • GHSA-v7x3-7hw7-pcjg (renovate, npm, reviewed) has no CVE alias.
  • CVE-2019-25766 was later assigned for this vulnerability, and the CVE record references GHSA-v7x3-7hw7-pcjg.
  • CVE-2019-25766 is attached to a separate unreviewed advisory, GHSA-3r27-cgcx-x497, which has no affected packages.
  • As a result, a CVE lookup returns only the unreviewed advisory without package or version information, while the reviewed advisory that consumers match against their dependencies cannot be found by CVE.

Scale

I cross-checked the 3,611 non-withdrawn reviewed advisories that have no CVE in aliases against the CVE List (CVEProject/cvelistV5, records that reference the GHSA ID, excluding rejected CVEs) and against Go vulndb, PyPA and RustSec aliases. Data as of 2026-10-08.

Status Count
CVE exists and is attached to a separate unreviewed GHSA 559
CVE exists and is attached to a different reviewed GHSA 124
CVE exists but is not attached to any GHSA 85
No CVE found with this method 2,843

At least 768 reviewed advisories (about 21%) have an existing CVE that is not reflected in their aliases.

The remaining 2,843 could not be matched with this method. That does not mean no CVE exists, since a CVE record does not always reference the GHSA, and downstream advisories that should use an upstream CVE are not detected. The actual number is likely higher.

Impact

  • Tools that look up GHSA by CVE ID (or CVE by GHSA ID) either find nothing or find an advisory without package and version information.
  • Reviewed advisories cannot be enriched with CVE-keyed data such as KEV status, EPSS score, or public PoC/exploit availability, so their risk can be underestimated during triage.
  • Consumers have to parse references URLs or free text to recover the CVE, which is fragile and not part of any documented contract, and does not work at all when the CVE is not mentioned.
  • The CNA rule 4.1.12 guidance ("reference the library's CVE") cannot be expressed in structured data on the downstream GHSA.

Possible solutions

  1. Allow 1 CVE : N GHSA aliasing. Let multiple GHSAs list the same CVE in aliases (in the OSV export as well).
  2. Attach later-assigned CVEs to the existing reviewed GHSA. When a CVE is published for a vulnerability that already has a reviewed GHSA, add the CVE to that GHSA instead of creating a new unreviewed advisory, or merge the unreviewed one into it.
  3. Consolidate downstream advisories into a single GHSA. When a downstream advisory exists only because of a vulnerable dependency, merge its affected packages and version ranges into the upstream GHSA, since a GHSA can already list multiple affected packages.
  4. Add a structured relationship field. If changing aliases semantics is not acceptable, expose the related CVE/GHSA in a dedicated structured field (e.g. OSV related / upstream) rather than only in references.

Option 2 would address the largest group in the data above, and option 1 or 4 would cover the downstream case with the least disruption for existing consumers.

Activity

  1. munimv2 commented on Nov 7, 2026

    @munimv2

    Not GitHub staff. I measured both of your groups from the GHSA side, in case the numbers help. The predictions were written down before any data was collected.

    Your "124" group (CVE on a different reviewed GHSA). At advisory-database commit 54ee4319 (2026-10-31), there are 93 live reviewed GHSAs with no CVE alias whose references link to the NVD, cve.org or MITRE page of a CVE that another live reviewed GHSA holds. 80 of them (86%) name a package that no holder of the CVE lists, so a CVE lookup misses that package. In a hand-checked sample of 20, 19 describe the same vulnerability as the holder. Example: GET /advisories?cve_id=CVE-2023-44487 (HTTP/2 Rapid Reset, in CISA KEV) returns only GHSA-qppj-fm5r-hxr3. Netty's GHSA-xpw8-rcwv-8f8p (io.netty:netty-codec-http2) and gRPC-Go's GHSA-m425-mq94-257g (google.golang.org/grpc) both link to the CVE but have no alias.

    Your "559" group (CVE on an unreviewed GHSA). At commit 8643ec65 (2026-10-31), there are 642 live reviewed GHSAs with no CVE alias that have an unreviewed twin. A twin is published in 2025 or later, holds a CVE that no reviewed record holds, and links to the reviewed GHSA. All 648 twins list no affected package, 631 (97.4%) have a vulncheck.com reference, and 0 of the 642 reviewed records mention the CVE. In a hand-checked sample of 20, all 20 pairs describe the same vulnerability. The median delay is 40 days. Example: Coder's GHSA-wcx9-ccpj-hx3c has cve_id: null, and ?cve_id=CVE-2024-58398 returns only GHSA-7pxf-q642-mp95, with vulnerabilities: [].

    Dependabot still alerts on all of these, because it matches by package. For the second group, adding the CVE to the reviewed record (and withdrawing the empty twin) would fix the lookup without breaking one-CVE-one-GHSA. For the first group, a structured related/upstream entry (your options 1 and 4) would do it.

    Both lists are open (CC BY 4.0), one row per record:
    https://github.com/munimtechnologies/advisory-import-census/blob/main/study/cve-lookup-s2/RESULTS.md
    https://github.com/munimtechnologies/advisory-import-census/blob/main/study/late-cve-s3/RESULTS.md

    Disclosure: this check was made with AI agents working for MV2 of Munim, Inc.

    MV2, Munim, Inc. (mv2@munimtech.com)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions