v5.0
live available
practices ranked 27 Sept 2026

Ten vulnerability feeds asked about one package, ranked by how usable the answer is

One urllib3 version, ten sources, four severities for a single CVE and two fix versions that do not exist upstream. What each feed can and cannot tell you.

By Purvansh Parmar Checked 2026-09-27 Read 8 min Entries 10

You have urllib3 1.26.17 in a lockfile and a ticket that says clear the criticals. Ask ten different vulnerability feeds about that exact version and you get back four severities for one CVE, two fix versions that exist in no upstream release, and a count that is wrong by a factor of two. None of them is lying. They answer different questions, and whichever one your scanner happens to query is the thing that decides what your build blocks on. Here is the order I would ask them in, and where each one stops being useful.

How this was checkedI pulled all ten of these on 2026-09-27 against the same target: urllib3 1.26.17, a version that still shows up in old deployment bundles. OSV and PyPI each returned 14 records covering 7 distinct CVEs. NVD gave CVE-2026-44431 two scores at once, 8.2 from the GitHub CNA under CVSS 4.0 and 5.3 from NIST under 3.1. Ubuntu says jammy is fixed at 1.26.5-1~exp1ubuntu0.2 and Debian says bookworm is fixed at 1.26.12-1+deb12u1, and no upstream range would accept either number. The Debian dump cost 212 seconds and 78.2 MB because there is no per-CVE endpoint.

What I compared on

01 GitHub Advisory Database

GitHub's curated advisory set, queryable over the public REST API by CVE or by package.

Wins
You hold a package and a version and you want the range and the first patched release. One call on CVE-2024-37891 returned urllib3 < 1.26.19 patched by 1.26.19, and >= 2.0.0, < 2.2.2 patched by 2.2.2. That is the whole pull request in two lines.
Loses
Unauthenticated calls are capped at 60 an hour, and the response headers showed 55 left after my fifth lookup. The severity it hands back is its own CNA score of 4.4, where NIST scores that same CVE 6.5.
60 requests per hour unauthenticated1.27s per lookupCVSS 4.4 against NIST 6.5

02 OSV.dev

An aggregator that takes a package and a version over POST and returns every advisory touching it.

Wins
Ecosystem-native version ranges across PyPI, npm, Go, crates and Maven, with no key and no signup. You query the version you actually have installed instead of a CVE you have to know first.
Loses
It returns the GHSA record and the PYSEC record for one flaw without collapsing them. urllib3 1.26.17 came back with 14 entries covering 7 real CVEs, so anything that counts the array reports double.
14 records for 7 CVEs3.97s, 51 KB responseno API key

03 Ubuntu CVE Tracker

Per-release fix status for every Ubuntu source package, served as JSON at a guessable URL.

Wins
It is the only feed that tells you how a fixed Ubuntu package is numbered. On CVE-2024-37891 it marks jammy released at 1.26.5-1~exp1ubuntu0.2 while upstream needs 1.26.19, which is the difference between a real finding and three days of arguing.
Loses
It rates on its own priority field rather than CVSS, and called this one low where Red Hat called it Moderate. Releases past end of life come back as ignored instead of resolved, so you have to read ESM coverage between the lines.
1.65s, 19.9 KBjammy fixed at 1.26.5-1~exp1ubuntu0.2priority low

04 Debian Security Tracker

Debian's per-release CVE status for the whole archive, published as a single JSON document.

Wins
Once you have it, nothing is ambiguous. Bookworm resolves both CVE-2024-37891 and CVE-2023-45803 in 1.26.12-1+deb12u1, one backport covering two flaws, and the file carries every source package at once so you can answer a fleet-wide question offline.
Loses
There is no per-CVE endpoint at all. The dump is 78.2 MB and took 212 seconds at 369 KB/s, and my first attempt with a 40 second timeout produced 4.9 MB of truncated JSON that died in the parser rather than reporting a failure.
78.2 MB, 212s4,039 source packages70,424 CVE entries

05 Red Hat Security Data API

Per-product fix state across every Red Hat offering, one JSON document per CVE.

Wins
It is the only source taht explains why you are not affected. Its CVE-2024-37891 statement points out that an .egg-info directory holds metadata and no code, which retires an entire class of false positives from image scanners.
Loses
Everything is keyed to Red Hat product names, so a 24.2 KB answer is a list of Ansible and OpenShift images rather than a version you can pin. Moderate and Important do not map onto a CVSS threshold without someone deciding where the line goes.
1.81s, 24.2 KBModerate, CVSS 4.4

06 PyPI JSON API

The package metadata endpoint, which carries a vulnerabilities array on every version document.

Wins
Fastest in the set at 0.48 seconds, and you are usually fetching this document anyway to resolve a version. No auth, no client library, no second service to keep alive in CI.
Loses
It is OSV underneath and inherits the duplication exactly: the same 14 records for 7 real CVEs. Python only, no severity field of any kind, and nothing about the distribution package of the same name.
0.48s, 76.5 KB14 records for 7 CVEs

07 NVD 2.0 API

The canonical CVE record with NIST enrichment, addressable one CVE identifier at a time.

Wins
This is where CPE match strings and the NIST score live, and it is honest enough to show every competing score beside the identifier of whoever assigned it. For auditors it is the document that ends the conversation.
Loses
You cannot ask it about a package version, only about a CVE you already knew to look up. CVE-2026-44431 carries a CVSS 4.0 of 8.2 from the GitHub CNA and a CVSS 3.1 of 5.3 from NIST, so a gate that fails the build on High fires or stays quiet depending on which metric block your scanner reads first.
1.5s to 3.5s per call8.2 High against 5.3 Medium398,483 CVEs

08 CISA KEV Catalog

The list of CVEs with confirmed exploitation in the wild, published as one small JSON file.

Wins
A boolean that reorders a backlog in an afternoon. None of the seven urllib3 CVEs my query returned are in it. Log4Shell is, and that is the distinction a severity column was never able to draw.
Loses
Catalogue 2026.09.25 holds 1,726 entries against 398,483 published CVEs, which is 0.43 percent, so absence proves almost nothing. It carries no fix version and no package identity, only the CVE and a due date aimed at federal agencies.
1,726 entries0.43% of all CVEscatalogue 2026.09.25

09 EPSS

A daily model scoring every CVE on the probability of exploitation in the next 30 days.

Wins
It splits apart two findings that look identical in a severity column. CVE-2024-37891 scores 0.01141 at the 65th percentile. Log4Shell scores 0.99999 at the 100th. A 203 byte response is enough to sort a quarter's worth of remediation.
Loses
It will not tell you whether you are affected or what to upgrade to, and 1.1 percent is not zero. Scores are recomputed daily, so a queue built on a fixed threshold reshuffles itself with no change to your code.
0.01141 for CVE-2024-378910.99999 for Log4Shell203 byte response

10 Safety DB

A curated Python vulnerability list published as a single JSON file in a public repository.

Wins
Offline and diffable. One 12.1 MB file covering 4,796 packages can be vendored and pinned, which is what makes a scan possible on a build host with no outbound network.
Loses
Updated monthly, and the newest data commit is dated 2026-09-01, so a fresh advisory can stay invisible for four weeks. It is licensed CC BY-NC-SA 4.0, which means no commercial use without buying a separate licence from the publisher.
12.1 MB, 30.6s4,796 packagesCC BY-NC-SA 4.0

Side by side

Upgrade to what?Knows backportsOne lookup
GitHub Advisory DBYes, exact rangeNo1.27s
OSV.devYes, duplicatedNo3.97s
Ubuntu CVE TrackerYes, distro versionYes1.65s
Debian TrackerYes, distro versionYes212s for 78.2 MB
Red Hat Security DataProduct state onlyYes1.81s
PyPI JSONYes, duplicatedNo0.48s
NVD 2.0No, CVE in onlyNo1.5s to 3.5s
CISA KEVNoNoone file
EPSSNoNo203 bytes
Safety DBYes, monthly staleNo30.6s for 12.1 MB

Verdict

Ask the GitHub Advisory Database first. It is the only feed that returns a vulnerable range and a first patched version in one call, in the ecosystem's own version syntax, and that is the sentence you paste into the pull request. Then find out whether the package came from the distribution or from pip. If it came from the distribution, believe the Ubuntu CVE Tracker over every upstream range, because a backport renders all of them wrong. Sort the remaining queue by EPSS. Keep NVD for the one CVE a week you have to argue about with someone holding a spreadsheet.

Sources