Yes. Compare the list of packages each scanner found before you look at a single vulnerability. A scanner cannot flag a flaw in a component it never identified, so an inventory gap explains many apparent detection gaps and is far easier to check.
Two stages hiding in one result
A dependency scanner does two jobs. First it extracts the packages from your project. Then it matches those packages against vulnerability data. The OSV-Scanner documentation describes exactly this two step process: package extraction, then vulnerability matching. See the usage page.
When results differ, the cause is either in stage one (different packages found) or stage two (same packages, different matching). If you only compare final findings, you cannot tell which stage failed. Compare stage one first and the fog clears.
How to run the inventory comparison
- Export a full package list from each tool, including packages with no vulnerabilities. Some tools offer a flag for this, and others produce an SBOM.
- Convert each row to a package URL and version. The purl specification defines the format and is the identifier used in CycloneDX and SPDX.
- Compare the three lists: your lockfile, scanner A, and scanner B.
- Sort the differences into buckets.
Your lockfile is the closest thing to ground truth for most ecosystems, because it records what the build will actually install. If a scanner reports a package that is not in the lockfile, or misses one that is, something is worth investigating.
What the gaps usually mean
| Gap | Common cause |
|---|---|
| Scanner misses packages in the lockfile | Unsupported file format or ecosystem, or the file was skipped |
| Scanner reports packages not in the lockfile | It resolved from a manifest range, or read a different file |
| Version differs for the same package | Manifest range resolved to a different version than the lockfile pins |
| Same name, different casing or separator | Normalization difference, not a real gap |
| Fewer packages overall | Transitive resolution off, or dev dependencies excluded |
Each of these has a different fix and a different meaning for your decision. A tool that skips a file format you rely on is a coverage problem. A tool that merely normalizes names differently is not.
Report inventory match as a number
Compute a simple figure per scanner: of the packages in your lockfile, what share did the tool identify, per ecosystem? Keep the denominator visible, for example "412 of 430." Do not round it into a percentage alone. Report it per repository and per ecosystem rather than as one global number, because averages hide a tool that does well in Node and poorly in Go.
Then compare vulnerabilities, restricted to shared packages
Once inventories are understood, compare vulnerability findings only on the packages both scanners found. That isolates matching quality from extraction quality. Then look separately at findings on packages only one tool identified. If scanner A found a vulnerable package that B never identified, that is a real inventory advantage for A, and it is worth counting for A.
This sequence also helps when you plant a known vulnerable package: if the planted package is missing from a tool's inventory, you know why before you see the result.
Try it yourself
Click through it at your own pace, or open it full screen. Notice that the inventory is a separate view from the findings.
Safeguard builds a dependency inventory and SBOM from your repositories, and you can see yours with the free scan at gold.safeguard.sh/scan.
Quick check
What if my repository has no lockfile?
Then ground truth is fuzzier. See the separate post on comparing scanners on repositories without lockfiles, and build the install yourself to get a reference list.
Is a bigger inventory always better?
No. Extra packages that are not actually installed are false inventory. Check a sample against the lockfile.
Sources
- OSV-Scanner usage: extraction then matching, and the all packages output option.
- Package URL specification: identifier format used in SBOMs and vulnerability databases.
Last reviewed: 19 October 2026.