When an open-source project fixes a vulnerability, it often publishes the details as a GitHub repository security advisory. That's the project's own announcement. Most dependency scanners don't read it. They read GitHub's global advisory database, or OSV, which mirrors the reviewed part of it, and an advisory only reaches those after GitHub reviews it. We measured how big that gap is in 2026.
We took the 45 projects that fed the most 2026 records into the database across Go, npm and PyPI, listed every repository advisory they published this year, 2,486 in all, and checked each one against OSV. This post is for teams that rely on database-fed scanners, and for maintainers who publish advisories. It covers the method, what we found, why the gap is mostly a backlog rather than a hole, and a script that shows the gap for any project you depend on.
The short answer
Of 2,486 repository advisories published in 2026 by 45 active open-source projects, 764 (30.7%) were not in GitHub's reviewed advisory database or OSV on 18 October 2026, across every severity level. Most of the gap is recent: under 8% of advisories from January to June are missing, against 25% to 63% from August and September and about 90% from October. Advisories that do arrive take a median of 5.4 days, and one in six takes more than 30. Advisories without a CVE are far more likely to be missing. If a project you depend on publishes repository advisories, check them directly: a clean scan can mean the database hasn't caught up.
How we measured it
- Pick the projects. From OSV's Go, npm and PyPI data dumps, we found the 1,368 GitHub repositories whose 2026 database records point back to a repository advisory, and took the 45 with the most records. These are the most active advisory publishers, not a random sample.
- List their advisories. For each, we fetched published repository advisories from the GitHub API, one page of up to 100 per project, and kept the 2,486 published in 2026. Eight projects hit the 100 limit, so for them we have their most recent 100.
- Check the database. We looked up each advisory ID in OSV, first in the dumps, then through the OSV API. As a spot check, we took eight random missing advisories and queried GitHub's global advisory API directly: all eight returned "not found".
We don't name projects in the results. The gap is about the pipeline between projects and databases, not about any project. Publishing many advisories is a sign of diligence, not of poor security.
What we found
| Measure | Result |
|---|---|
| 2026 repository advisories checked | 2,486 from 45 projects |
| Not in GitHub's reviewed database or OSV | 764 (30.7%) |
| Same, excluding the 8 projects capped at 100 | 21.2% of 1,686 |
| Missing, by severity | critical 31.2%, high 29.3%, medium 32.2%, low 29.3% |
| Missing, advisories with a CVE | 194 of 1,745 |
| Missing, advisories without a CVE | 570 of 741 |
| Median delay for advisories that arrived | 5.4 days |
| Arrived the same day / after more than 30 days | 18.9% / 16.8% |
| Missing advisories older than 30 days | 469 |
| Projects with nothing missing / with half or more missing | 5 / 5 |
Two things stand out. Severity makes no difference: critical advisories are as likely to be missing as low ones. And a CVE makes a large one: 77% of advisories without a CVE are missing, against 11% of those with one.
Mostly a backlog, not a black hole
The monthly view changes the picture:
| Published | Advisories | Missing on 18 Oct |
|---|---|---|
| January | 60 | 3% |
| February | 66 | 20% |
| March | 232 | 6% |
| April | 178 | 1% |
| May | 224 | 3% |
| June | 357 | 8% |
| July | 321 | 15% |
| August | 434 | 46% |
| September | 393 | 63% |
| October (to the 18th) | 221 | 93% |
Of the 1,117 advisories published before July, 6% are still missing, including eight rated critical. The database does catch up. But the backlog has grown since midsummer, so on the day we measured, a scanner fed by the database couldn't see most advisories from the past two months for these projects. Excluding the eight capped projects softens the recent months (25% for August, 38% for September) without changing the shape.
This matches what we've seen case by case. One project fixed four security issues in a September release, and a month later only the one with a CVE was in the database. Another project's August batch of advisories reached the database 40 days later.
Check the projects you depend on
This script lists a project's published repository advisories and marks the ones OSV doesn't have, with their age. It uses only the Python standard library. Set GITHUB_TOKEN to raise GitHub's limit of 60 requests an hour:
#!/usr/bin/env python3
"""List a project's GitHub repository advisories and show which ones scanners can't see yet.
advisory_gap.py OWNER/REPO [OWNER/REPO ...]
Reads the repository's published security advisories from the GitHub API and asks OSV
(which mirrors GitHub's reviewed advisory database) about each one. Set GITHUB_TOKEN to
raise the API limit from 60 requests an hour. Standard library only.
"""
import datetime as dt, json, os, sys, urllib.error, urllib.request
def get(url, headers=None):
req = urllib.request.Request(url, headers={"User-Agent": "advisory-gap", **(headers or {})})
with urllib.request.urlopen(req, timeout=30) as r:
return json.load(r)
def gh_headers():
h = {"Accept": "application/vnd.github+json"}
if os.environ.get("GITHUB_TOKEN"):
h["Authorization"] = "Bearer " + os.environ["GITHUB_TOKEN"]
return h
def in_osv(ghsa):
try:
return get(f"https://api.osv.dev/v1/vulns/{ghsa}").get("published", "")[:10]
except urllib.error.HTTPError as e:
if e.code == 404:
return None
raise
def main(repos):
today = dt.date.today()
hidden = 0
for repo in repos:
advs = get(f"https://api.github.com/repos/{repo}/security-advisories?state=published&per_page=100", gh_headers())
print(f"{repo}: {len(advs)} published repository advisories")
for a in sorted(advs, key=lambda a: a.get("published_at") or "", reverse=True):
pub = (a.get("published_at") or "")[:10]
seen = in_osv(a["ghsa_id"])
age = (today - dt.date.fromisoformat(pub)).days if pub else 0
status = f"in database since {seen}" if seen else f"NOT IN DATABASE ({age} days)"
hidden += not seen
print(f" {pub} {a['ghsa_id']} {(a.get('severity') or '?'):8} {(a.get('cve_id') or 'no CVE'):16} {status}")
print(f"{hidden} advisory(ies) a database-fed scanner would not report")
return 1 if hidden else 0
if __name__ == "__main__":
if len(sys.argv) < 2:
sys.exit(__doc__)
sys.exit(main(sys.argv[1:]))
On SFTPGo, which documents every security fix in its release notes and advisories:
$ python3 advisory_gap.py drakkan/sftpgo
drakkan/sftpgo: 16 published repository advisories
2026-09-19 GHSA-5jhj-cjcp-jr8r medium no CVE NOT IN DATABASE (29 days)
2026-09-19 GHSA-wwv9-g5x4-966q medium CVE-2026-103028 in database since 2026-10-15
2026-09-19 GHSA-f9qc-3v4f-32w3 high no CVE NOT IN DATABASE (29 days)
2026-09-19 GHSA-j4w8-6gjf-fqvg medium no CVE NOT IN DATABASE (29 days)
2026-07-17 GHSA-q7pc-356p-hggc medium CVE-2026-77375 in database since 2026-10-15
2026-06-29 GHSA-fj9v-mxr3-w75w medium no CVE NOT IN DATABASE (111 days)
2026-05-30 GHSA-h64p-8h4r-6gfh medium CVE-2026-49244 in database since 2026-07-02
2026-05-30 GHSA-3vcg-pv95-pq54 low CVE-2026-49245 in database since 2026-07-02
2026-03-13 GHSA-x8qh-7475-c5mp medium CVE-2026-30914 in database since 2026-03-13
2026-03-13 GHSA-m83q-5wr4-4gfp medium CVE-2026-30915 in database since 2026-03-13
2025-02-07 GHSA-vj7w-3m8c-6vpx high CVE-2025-24366 in database since 2025-02-07
2024-11-28 GHSA-6943-qr24-82vx medium CVE-2024-52801 in database since 2024-12-02
2024-11-21 GHSA-49cc-xrjf-9qf7 medium CVE-2024-52309 in database since 2024-11-21
2024-06-20 GHSA-hw5f-6wvv-xcrh medium CVE-2024-37897 in database since 2024-06-20
2022-09-17 GHSA-cf7g-cm7q-rq7f medium CVE-2022-39220 in database since 2022-09-20
2022-09-01 GHSA-54qx-8p8w-xhg8 medium CVE-2022-36071 in database since 2022-09-16
4 advisory(ies) a database-fed scanner would not report
(exit 1)
Four of its 16 advisories, including a high-severity cross-site scripting fix from September, weren't visible to database-fed scanners on the day we ran it. That isn't a criticism of the project, which published all four. It shows why reading the source matters for software you run.
If you track advisories against the versions you actually run, a watch view helps you triage what's new. Here's Safeguard's interactive walkthrough of one:
What to do
- List your critical open-source dependencies that publish GitHub repository advisories, especially self-hosted applications and frameworks.
- Check them directly, with the script above in CI or on a schedule, and subscribe to their security advisories on GitHub.
- Don't read a clean scan as "no advisories". It means none the database knows about yet. Our post on what npm audit misses covers the other gaps.
- If you maintain a project, request a CVE when you publish an advisory. In our data, advisories with a CVE reached the database far more often. GitHub can assign one from the advisory form.
- Read how the database works. Our explainer on how GitHub's advisory database is curated covers the review step behind the delay.
The fair view
GitHub's reviewed advisory database is one of the best public sources of package vulnerability data, and the review step is why its records are accurate and machine-readable. Reviewing thousands of advisories with correct package names and version ranges takes time, and the January to June numbers show that most advisories do make it. Part of the recent backlog may also be advisories that don't name a package, which a package database can't match anyway. We didn't separate those out.
The limits of this study cut both ways. These 45 projects are the most active publishers, so their numbers may not match a typical project's. But they're also the projects whose advisories scanners are most likely to need. The practical conclusion holds either way: for the software that matters most to you, the project's own advisory page is the primary source, and the database is a copy that runs behind it.
Check yourself
Your scanner shows no findings for a project that published an advisory last week. What's the most likely reason?
The advisory probably hasn't been reviewed into GitHub's global database yet. In our data, a median advisory took 5.4 days to arrive, one in six took more than 30, and most advisories from the last two months hadn't arrived at all. Check the project's advisory page directly.
Which mattered more for whether an advisory reached the database: severity or having a CVE?
Having a CVE. Missing rates were almost identical across severities, around 30%, but 77% of advisories without a CVE were missing, against 11% of those with one.
You maintain an open-source project. What one step makes your advisories more visible to scanners?
Request a CVE when you publish the advisory, and fill in the affected package and version range. Both make the advisory easier to review and match, and in our data advisories with a CVE reached the database far more often.