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.
Summary
filterPackageVulnsinpkg/osvscanner/filter.gocontains a logic guard that silently drops vulnerabilities when allGroupsentries are filtered out by the ignore configuration — even if those vulnerabilities were not explicitly ignored.Root Cause
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) == 0causes the entire vulnerability loop to be skipped. Any vulnerability whose ID is not present inignoredVulns(i.e., not referenced by any group'sAliases) is silently dropped rather than preserved.Reproduction (pseudo-code)
Fix
Remove the guard — the
ignoredVulnsmap already handles filtering correctly on its own, and the loop is cheap: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.