Advisory grouping
How Basilisk groups OSV and NVD records that refer to the same CVE.
OSV and NVD often describe the same vulnerability under different IDs. OSV may use a GHSA ID and list the CVE as an alias, while NVD uses the CVE ID directly.
Basilisk groups those records for the API and explorer, but keeps the original source records as they are.
Grouping is a view over source records
OSV and NVD still own their records. Basilisk keeps the original IDs and data, so you can trace a grouped response back to each source.
Choosing the canonical ID
Check the aliases
If an advisory has one or more CVE aliases, Basilisk sorts them and takes the first one.
Fall back to the source ID
If there is no CVE alias, Basilisk uses the source advisory ID. Advisories without a CVE still get a stable ID this way.
Group matching IDs
Advisories with the same canonical ID are shown as one group.
Worked example: GHSA and NVD
Here is a real example from Pillow. OSV uses GHSA-3f63-hfp8-52jq, while NVD uses CVE-2023-50447.
{
"id": "GHSA-3f63-hfp8-52jq",
"aliases": ["CVE-2023-50447"],
"affected": [{
"package": { "ecosystem": "PyPI", "name": "Pillow" }
}]
}The CVE alias makes CVE-2023-50447 the canonical ID.
{
"source": "nvd",
"id": "CVE-2023-50447",
"source_url": "https://nvd.nist.gov/vuln/detail/CVE-2023-50447"
}NVD already uses the CVE as its source ID, so both records end up in the same group.
The API returns one canonical ID and keeps the GHSA ID as an alias:
{
"id": "CVE-2023-50447",
"aliases": ["GHSA-3f63-hfp8-52jq"],
"affected": [
{ "package": { "ecosystem": "PyPI", "name": "Pillow" } },
{ "package": { "ecosystem": "conda-forge", "name": "pillow" } }
]
}This is shortened a bit. The real response also includes severity, references, timestamps, ranges, and match metadata.
The canonical ID is only used to group and display the records. Each member keeps its own source ID, timestamps, affected data, and references.
What gets combined
The OSV-compatible response combines a few fields from the group:
- The canonical ID becomes the document ID.
- Source IDs and aliases are collected into
aliases. - Severities are kept and deduplicated.
- References are deduplicated by URL.
- The earliest publication time and latest modification time are used.
- Affected entries from the source records are kept.
- Matched conda-forge packages and versions are added as affected entries.
Some fields, such as the summary and details, need one source. Basilisk prefers an OSV record when one is available. The REST response still lists the source IDs and source kinds, and each match keeps its own provenance.
Grouping match results
Matching happens against source advisories first. Grouping happens afterwards.
Two records in the same group can still produce different evidence. One may match through a PURL and an OSV range. Another may match through a CPE and an NVD range. Basilisk keeps both match rows and shows them under the same canonical advisory.
Package-specific advisory lists use one row per (package, canonical advisory). If that package/group pair has several applicability values, Basilisk picks them in this order:
evaluatedunevaluatedversion_unbounded
The global GET /v1/advisories browse endpoint has a different cardinality: one row per canonical advisory across all matched packages. It groups first, then applies search and source/severity filters, computes saved-view totals, sorts, and selects the requested bounded window. Each row reports the distinct matched-package count and retains source-attributed severity records. Package-specific remediation is intentionally absent because one canonical advisory can have different fixes and conda-forge publication states for different packages.
The grouped detail still includes the individual source matches and their provenance. For example, an evaluated OSV/PURL match wins over a version_unbounded NVD/CPE match in a package-specific list. The NVD match is still there when you open the grouped detail.
Looking up an advisory
GET /v1/vulns/{id} and the advisory detail route accept:
- the canonical ID,
- a source advisory ID,
- a known alias.
All three open the same grouped advisory, so clients can use whichever identifier they already have.
