google / google/osv-scanner

SARIF output emits one result per matched advisory in an alias group, creating duplicate code scanning alerts

Open Beginner friendly
#3,093 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
11k
Forks
792
Avg merge
1d 20h
Merged PRs (30d)
48

Description

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+incompatible
```

```sh
osv-scanner scan source --format=sarif --output=results.sarif -L go.mod
jq -r '.runs[0].results | group_by(.ruleId)[] | "\(.[0].ruleId) x\(length)"' results.sarif
```

Output, 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 x2
```

That 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 `partialFingerprints` to 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 `BuildResults` formatters (table, vertical, Markdown, HTML) caused by ecosystem prefix collisions. SARIF does not use that code path.

Best, Philip

Contributor guide

Open the contributing guide

Research direction

Start with internal/output/result.go at mapIDsToGroupedSARIFFinding and internal/output/sarif.go at PrintSARIFReport and run.AddRule. Reproduce the issue with the provided go.mod and osv-scanner scan command, then verify that SARIF emits one result per alias group while preserving one rule per group and the existing table behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
github, go
Domain
cli, security
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
88/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.