Skip to content

filterPackageVulns: orphan vulnerabilities silently dropped when all groups are ignored #2756

@hyhmrright

Description

@hyhmrright

Summary

filterPackageVulns in pkg/osvscanner/filter.go contains a logic guard that silently drops vulnerabilities when all Groups entries are filtered out by the ignore configuration — even if those vulnerabilities were not explicitly ignored.

Root Cause

var newVulns []*osvschema.Vulnerability
if len(newGroups) > 0 { // ← problematic guard
    for _, vuln := range pkgVulns.Vulnerabilities {
        if _, filtered := ignoredVulns[vuln.GetId()]; !filtered {
            newVulns = append(newVulns, vuln)
        }
    }
}

The comment reads: "If there are no groups left then there would be no vulnerabilities." This is an assumption, not an invariant. When all groups are ignored, len(newGroups) == 0 causes the entire vulnerability loop to be skipped. Any vulnerability whose ID is not present in ignoredVulns (i.e., not referenced by any group's Aliases) is silently dropped rather than preserved.

Reproduction (pseudo-code)

Input:
  Groups:          [ G1{ Aliases: ["CVE-2024-001"] } ]
  Vulnerabilities: [ {ID: "CVE-2024-001"}, {ID: "CVE-2024-999"} ]
  Ignore config:   ignore "CVE-2024-001"

After group filtering:
  newGroups    = []                    ← all groups ignored
  ignoredVulns = {"CVE-2024-001": {}} ← only the explicitly ignored IDs

Vulnerability loop:
  len(newGroups) > 0 → false → loop skipped entirely

Actual result:   Vulnerabilities = []            ❌
Expected result: Vulnerabilities = [CVE-2024-999] ✅

Fix

Remove the guard — the ignoredVulns map already handles filtering correctly on its own, and the loop is cheap:

var newVulns []*osvschema.Vulnerability
for _, vuln := range pkgVulns.Vulnerabilities {
    if _, filtered := ignoredVulns[vuln.GetId()]; !filtered {
        newVulns = append(newVulns, vuln)
    }
}

This change is strictly safer: if the groups-always-cover-all-vulns invariant holds in practice, the output is identical. If it ever breaks (data inconsistency, future schema changes), vulnerabilities are correctly preserved rather than silently lost.


Found using Logic-Lens — a semi-formal logic bug detection skill for Claude Code / Gemini CLI / Codex CLI.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions