Send the package name, its ecosystem and its exact installed version to the public OSV query endpoint. It returns the vulnerability records that affect that version, including the version where each was fixed. It takes one command and gives you an independent check on any scanner's answer for an operating system package in your image.
Why do this at all
When a scanner reports a finding you doubt, or reports nothing where you expected something, you need a second opinion that does not depend on the tool. OSV is an open database that aggregates advisories, including operating system distributions. Its API is public and needs no account. A hand check takes a minute and tells you whether the scanner or your assumption is wrong.
It is also a good trial technique. Pick five packages from a test image, check each by hand, and compare with each candidate scanner. Differences show you which tools handle distribution data well.
What you need
Three values from the image.
- The package name, as the package manager lists it.
- The exact installed version, with revision suffix. Do not tidy it.
- The ecosystem string for the image's operating system release, written the way OSV writes it, for example an Alpine branch or a Debian release number.
OSV's records show the pattern. A record we fetched for a Debian issue lists the affected ecosystem as Debian with a release number, and one for Alpine lists Alpine with a branch label. Use the same form in your query.
The request
A query is a small JSON body sent with a POST. Here is the shape, using an Alpine package.
curl -s -d '{"package":{"name":"apache2","ecosystem":"Alpine:v3.21"},"version":"2.4.50-r0"}' https://api.osv.dev/v1/query
The response is a list of vulnerability objects. Each has an id, a summary or details, a published date, references, and an affected section. In the affected section, the ranges show events such as introduced and fixed, with the version in which the fix landed.
A real result
When we ran the query above, it returned 93 records for apache2 2.4.50-r0 on the Alpine v3.21 branch. The first by identifier was ALPINE-CVE-2021-42013, whose upstream identifier is CVE-2021-42013. Looking up that record shows it was published on 7 October 2021 and lists a fixed version of 2.4.51-r0 on several branches.
That matches the Alpine security file, where the 2.4.51-r0 entry lists CVE-2021-42013. Two independent routes, one answer.
We also queried the newest version that appeared in that Alpine file, 2.4.69-r0. At the time of writing the response was an empty object, which means OSV had no record affecting that version in that ecosystem. Empty is not the same as safe, and the next section explains why.
How to read the answer
| What you see | What it means | What to do |
|---|---|---|
| Records returned | Known issues affect this version | Read each fixed version and compare |
| Empty result | No record in this ecosystem for this version | Check the ecosystem string and the version string, then consider other sources |
| Records you did not expect | Your version is older than you thought, or the ecosystem is wrong | Recheck the package list of the image |
| Fewer records than the scanner shows | The scanner may use more sources, or you used the wrong ecosystem | Compare by CVE identifier |
Why an empty answer proves little
An empty result means this one database has nothing for that name, ecosystem and version. Three things can cause that.
- The ecosystem string is slightly wrong, so the lookup matches nothing.
- The package name in your image differs from the name the database uses, for example a binary name where it expects a source name. Debian data, for instance, is written against source packages.
- A newer vulnerability has not been recorded yet.
So treat empty as "nothing found here," and add a second source before you conclude anything.
Step by step: spot check a scanner
- Pick five packages from a test image, including one old, one new and one with a revision suffix.
- Query OSV for each with the exact version and the right ecosystem.
- Collect the CVE identifiers returned. OSV records often carry the CVE in an upstream field.
- Run the scanner on the same image and collect its CVE list for those packages.
- Compare. List CVEs only in OSV and CVEs only in the scanner.
- For each difference, find out why. Possible reasons include a different data source, an unfixed issue the scanner reports, or a version comparison error.
Common mistakes
- Using a tag or the upstream version instead of the exact installed version.
- Querying the wrong branch or release.
- Treating OSV as complete. It is one source.
- Forgetting that the same CVE can appear under several record identifiers, so count by CVE.
Try it yourself
Click through it at your own pace, or open it full screen.
Pick one finding in the demo and note its package name and version. That is the pair you would send to the query above.
Where Safeguard fits
Safeguard reports the installed and fixed version for each finding, which gives you the inputs for a check like this. You can try a free scan at gold.safeguard.sh/scan.
Quick check
Do I need an account or key to query OSV?
The query endpoint we used needed no key. Check the OSV documentation for current terms and limits before you automate heavy use.
Why does one CVE appear under more than one record id?
Different sources and ecosystems publish their own records for the same underlying CVE, usually listing it as upstream. Count by CVE identifier to avoid double counting.
If OSV returns nothing, can I ignore the package?
No. It only means this database has no match. Check the ecosystem string, the package name, and a second source.
Sources
Last reviewed: 19 October 2026.