SARIF output emits one result per matched advisory in an alias group, creating duplicate code scanning alerts
Hey,
We recently added the OSV Scanner GitHub Action to Distr, but it reports a lot duplicates (https://github.com/distr-sh/distr/security/code-scanning).
Happy to draft a pr in order to fix the issue.
Summary
--format=sarif emits one result per matched advisory ID within an alias group instead of one result per group. Each of those results carries the group's DisplayID as ruleId, the same location, the same message and the same partialFingerprints, so a consumer cannot tell them apart. GitHub code scanning opens one alert per result, so a package matched by both a GHSA and a GO entry for the same CVE produces two identical alerts that have to be dismissed individually.
The table output is unaffected, because it prints one row per alias group. That makes the duplication invisible in the workflow log and visible only in the Security tab.
Version
osv-scanner 2.6.0, run through ghcr.io/google/osv-scanner-action:v2.6.0. Also reproducible with the standalone CLI.
Reproduction
go.mod:
module example.com/repro
go 1.24
require github.com/docker/docker v28.5.2+incompatibleosv-scanner scan source --format=sarif --output=results.sarif -L go.mod
jq -r '.runs[0].results | group_by(.ruleId)[] | "\(.[0].ruleId) x\(length)"' results.sarifOutput, with advisory data as of 2026-09-16:
CVE-2026-33997 x2
CVE-2026-34040 x1
CVE-2026-41567 x2
CVE-2026-41568 x2
CVE-2026-42306 x2That is 5 rules and 9 results. CVE-2026-41567 is matched through two entries that alias each other, GHSA-x86f-5xw2-fm2r and GO-2026-5746, and is emitted twice. CVE-2026-34040 is matched through GO-2026-4887 only and is emitted once. The two results for a doubled rule are identical in ruleId, locations, message.text and partialFingerprints.primaryLocationLineHash.
Root cause
mapIDsToGroupedSARIFFinding registers one map key per matched advisory ID, all pointing at the same group object:
https://github.com/google/osv-scanner/blob/v2.6.0/internal/output/result.go#L229-L231
PrintSARIFReport then iterates over every key of that map and appends a result per iteration:
https://github.com/google/osv-scanner/blob/v2.6.0/internal/output/sarif.go#L259-L267
run.AddRule(gv.DisplayID) deduplicates by rule ID, which is why the rule count stays at one per group while the result count grows:
https://github.com/google/osv-scanner/blob/v2.6.0/internal/output/sarif.go#L301
The CVE never becomes a key itself, since gi.IDs holds only the IDs of matched entries, so the number of duplicates equals the number of matched advisories in the group rather than the length of the alias list.
Expected behaviour
One SARIF result per alias group, per package and source, matching what the table output reports.
Suggested fix
Skip a group that has already been emitted in that loop, for example with a seen map[*groupedSARIFFinding]bool, which preserves the deterministic ordering that the sorted key iteration provides.
Related
- #2331 added
partialFingerprintsto fix duplicates in GitHub's output. It cannot help here, because these duplicate results are byte-identical, including the fingerprint. - #3086 covers duplicate packages in the
BuildResultsformatters (table, vertical, Markdown, HTML) caused by ecosystem prefix collisions. SARIF does not use that code path.
Best, Philip
Source: google/osv-scanner