Two scanners disagree because they read different inputs, use different vulnerability data, and match versions differently. Neither is automatically wrong. To reconcile them, compare the dependency lists first, then the advisory sources, then the matching rules, and settle each difference with the advisory text.
Cause 1: they did not see the same dependencies
This is the most common reason. One tool reads the lockfile. Another resolves the manifest fresh and picks newer versions. A third inspects the built container. They produce three inventories, so of course they produce three result sets.
Check first: export each tool's component list and diff them. If the lists differ, stop and explain that before looking at any vulnerability.
Cause 2: different vulnerability data
There is no single complete vulnerability database. Aggregators such as osv.dev collect data from databases that use the OpenSSF vulnerability format, while other tools rely on different feeds or their own curated research. A flaw may appear in one source days before another. Severity scores and affected version ranges also vary between sources.
Cause 3: different matching rules
Even with the same list and the same advisory, tools can disagree about whether version 2.3.1 is affected. Reasons include how they parse version ranges, how they treat distribution patches that keep an old version number, and how they handle package names that differ between ecosystems.
Cause 4: different scope
| Setting | Effect |
|---|---|
| Dev dependencies included or not | Different counts |
| Transitive depth | Missing deep findings |
| Unreachable code reported or filtered | Large swing in volume |
| Container base layers scanned or not | Extra OS package findings |
A reconciliation routine
- Pick one repo and one commit. Pin both tools to it.
- Diff the component lists. Resolve every difference.
- Take the findings present in only one tool.
- For each, read the advisory and check whether the version you run is in the affected range.
- Mark it true positive, false positive, or unknown, and note which tool was right.
- Repeat on two more repos, then look for a pattern.
Patterns matter. If one tool consistently misses a certain ecosystem, that is a coverage fact you can plan around.
What to do with the result
Do not average the tools. Decide which is authoritative per ecosystem, and document the rule. Where the two disagree on a high severity item, assume the worse until an owner checks it.
You can also add exploitation context to break ties. CISA recommends using its Known Exploited Vulnerabilities catalog as an input to prioritization, so a finding that appears there deserves attention whichever tool raised it.
A worked example
Take a hypothetical Node project. Scanner A reports twelve findings. Scanner B reports seven. Only five are in both. The team sits down with the same commit and works through the routine.
First, they export both component lists. Scanner A resolved the manifest fresh and picked newer minor versions of two packages than the lockfile pins. Scanner B read the lockfile. That explains three of the differences, and the team decides the lockfile is the truth, since that is what ships. They re-run A in lockfile mode, and its list drops to ten findings.
Next they look at the five findings that appear only in A. Two concern a development only tool that never reaches production. B excludes development dependencies by default. The team decides to report them separately instead of dropping them. One comes from an advisory that B's data source did not yet include. The advisory is real and the version is in range, so A was right. Two more are for a package whose name collides with another ecosystem's package. A matched on name alone, which makes those false positives.
Then they check the two findings only in B. Both rely on a vendor curated record that A's sources lack. The team reads the vendor's explanation and agrees.
The end result: a documented rule that lockfile mode is the standard, development findings are tracked separately, and each tool's known gap is written down.
Disagreement log template
Keep a log. Over a few repositories, patterns appear.
| Finding | In A | In B | Cause | Verdict |
|---|---|---|---|---|
| Library X advisory | Yes | No | B data lagged | A correct |
| Library Y advisory | Yes | Yes | None | Both |
| Package Z | Yes | No | Name collision | A false positive |
After ten to twenty rows you can tell which tool you trust for which ecosystem.
When data freshness matters
A difference in timing is common right after an advisory is published. Aggregators and vendor databases update at different speeds, and some advisories get their affected version ranges corrected after publication. If a high severity item appears in only one tool, check the advisory date and the source before dismissing it. The cost of a quick look is small, and the cost of dismissing a real one is not.
Practical rules to adopt
- Pin the resolution method. Prefer lockfile based results because they reflect what ships.
- Separate production and development findings in reports.
- Record which data sources each tool uses.
- Treat a one tool only high severity finding as real until an owner checks it.
- Revisit the log each quarter as tools and data change.
Try it yourself
Click through it at your own pace, or open it full screen. Open the demo and look at how each finding keeps its source and status. That record makes later reconciliation much easier.
Safeguard offers SBOM and dependency scanning and reachability analysis, and you can compare its output on your repo using the free scan at gold.safeguard.sh/scan.
Quick check
Should I run two scanners on purpose?
For a short evaluation, yes. Permanently, only if each covers something the other does not.
Which tool is right when they disagree?
Neither by default. The advisory text and your actual version decide.
Does a disagreement mean one tool is broken?
Not usually. Most differences trace to inputs, data timing, or scope. Reconcile one commit at a time to find the cause.
Sources
Last reviewed: 19 October 2026.