What would you like to be added
Expose the matches that grype produces and then drops via the distro-fixed ownership rule (OwnershipIgnores invoked with reason "DistroPackageFixed" at grype/matcher/internal/distro.go#L105) through the ignoredMatches return of VulnerabilityMatcher.FindMatchesContext, the same way user-provided ignore rules already are.
Today the drop happens here in grype/vulnerability_matcher.go#L255-L256:
filtered, dropped := match.ApplyIgnoreFilters(allMatches, ignoredMatchFilter(allIgnorers))
logIgnoredMatches(dropped)
The dropped slice is logged and then discarded. The request is to flow it back to the caller instead.
Two reasonable shapes:
- Always include dropped matches in
ignoredMatches, with an IgnoreRule carrying the distro package, secfix version, and a reason such as DistroPackageFixed so consumers can render "suppressed because <distro-package> is FIXED for <vuln> at <version>". Simpler change, lights up --show-suppressed automatically.
- Add an opt-in flag on
VulnerabilityMatcher (for example IncludeDistroSuppressed bool) and a matching CLI flag (for example --include-distro-suppressed) that flips the dropped set into ignoredMatches. Slightly more conservative, same downstream effect.
Either shape unblocks the use case below; the first is simpler and is consistent with how user-rule-ignored matches behave today.
Why is this needed
We rely on grype to validate that remediations on our APK packages stay remediated. Since v0.110.0 ( #3282 ), a FIXED entry in our distro security feed for an APK suppresses the same CVE on every component bundled inside that APK on every subsequent rebuild. This is the right default for reducing noise, but the suppression is silent: the dropped matches do not appear in ignoredMatches, so they are invisible to --show-suppressed and to SDK consumers.
The downstream effect is that once a FIXED entry lands in security.json for an APK at version X-rN, every subsequent rebuild of that APK is implicitly assumed to preserve the fix. If a rebuild downgrades a bundled stdlib or vendored module to a version that re-introduces the CVE, grype reports no findings and there is no signal that a regression occurred. The blindspot is permanent for any APK that has ever had a FIXED secfix entry, across every component bundled inside it (Go modules, stdlib, Python packages, Java jars, Node modules).
Exposing the dropped set via ignoredMatches lets downstream consumers cross-check internal advisory state against grype's own assertion and reopen an advisory when the bundled-component state diverges, without having to re-implement the matching logic on the consumer side.
Additional context
Ignored vs dropped
The two kinds of filtered matches are intentionally distinguished in grype/vulnerability_matcher.go#L246-L248:
// note: there is a difference between "ignore" and "dropped" matches.
// ignored: matches that are filtered out due to user-provided ignore rules
// dropped: matches that are filtered out due to hard-coded rules
ignored flows back to callers via the second return of FindMatches / FindMatchesContext. dropped is captured by filtered, dropped := match.ApplyIgnoreFilters(...) and then discarded after logIgnoredMatches(dropped).
Worked example
CVE-2026-25679 affects the Go stdlib and is fixed in 1.25.8 / 1.26.1 (see GO-2026-4601).
-
fuse-overlayfs-snapshotter-2.1.7-r3 was published with go 1.25.8+ and a FIXED secfix entry was published. The Chainguard security feed at https://packages.cgr.dev/chainguard/security.json records:
"2.1.7-r3": [
"CVE-2026-25679",
...
]
-
fuse-overlayfs-snapshotter-2.1.7-r7 was rebuilt with go 1.24.13. The stdlib in r7 is again vulnerable to CVE-2026-25679.
Running this on r7:
grype --show-suppressed fuse-overlayfs-snapshotter-2.1.7-r7.apk
returns no findings and no ignored matches. The CPE match for cpe:2.3:a:golang:go:1.24.13 against the DB entry cpe:2.3:a:golang:go:* with constraint < 1.25.8 || >= 1.26.0-0, < 1.26.1 is produced by the matcher and then dropped, because the containing APK has a FIXED secfix record at r3 and r7 satisfies >= 2.1.7-r3. Today there is no way for a caller to see that match.
This same shape applies to every bundled language package inside any APK that has ever had a FIXED secfix entry.
References
What would you like to be added
Expose the matches that grype produces and then drops via the distro-fixed ownership rule (
OwnershipIgnoresinvoked with reason"DistroPackageFixed"atgrype/matcher/internal/distro.go#L105) through theignoredMatchesreturn ofVulnerabilityMatcher.FindMatchesContext, the same way user-provided ignore rules already are.Today the drop happens here in
grype/vulnerability_matcher.go#L255-L256:The
droppedslice is logged and then discarded. The request is to flow it back to the caller instead.Two reasonable shapes:
ignoredMatches, with anIgnoreRulecarrying the distro package, secfix version, and a reason such asDistroPackageFixedso consumers can render "suppressed because<distro-package>is FIXED for<vuln>at<version>". Simpler change, lights up--show-suppressedautomatically.VulnerabilityMatcher(for exampleIncludeDistroSuppressed bool) and a matching CLI flag (for example--include-distro-suppressed) that flips the dropped set intoignoredMatches. Slightly more conservative, same downstream effect.Either shape unblocks the use case below; the first is simpler and is consistent with how user-rule-ignored matches behave today.
Why is this needed
We rely on grype to validate that remediations on our APK packages stay remediated. Since
v0.110.0( #3282 ), a FIXED entry in our distro security feed for an APK suppresses the same CVE on every component bundled inside that APK on every subsequent rebuild. This is the right default for reducing noise, but the suppression is silent: the dropped matches do not appear inignoredMatches, so they are invisible to--show-suppressedand to SDK consumers.The downstream effect is that once a FIXED entry lands in
security.jsonfor an APK at versionX-rN, every subsequent rebuild of that APK is implicitly assumed to preserve the fix. If a rebuild downgrades a bundled stdlib or vendored module to a version that re-introduces the CVE, grype reports no findings and there is no signal that a regression occurred. The blindspot is permanent for any APK that has ever had a FIXED secfix entry, across every component bundled inside it (Go modules, stdlib, Python packages, Java jars, Node modules).Exposing the dropped set via
ignoredMatcheslets downstream consumers cross-check internal advisory state against grype's own assertion and reopen an advisory when the bundled-component state diverges, without having to re-implement the matching logic on the consumer side.Additional context
Ignored vs dropped
The two kinds of filtered matches are intentionally distinguished in
grype/vulnerability_matcher.go#L246-L248:ignoredflows back to callers via the second return ofFindMatches/FindMatchesContext.droppedis captured byfiltered, dropped := match.ApplyIgnoreFilters(...)and then discarded afterlogIgnoredMatches(dropped).Worked example
CVE-2026-25679 affects the Go stdlib and is fixed in
1.25.8/1.26.1(see GO-2026-4601).fuse-overlayfs-snapshotter-2.1.7-r3was published with go 1.25.8+ and a FIXED secfix entry was published. The Chainguard security feed at https://packages.cgr.dev/chainguard/security.json records:fuse-overlayfs-snapshotter-2.1.7-r7was rebuilt with go 1.24.13. The stdlib in r7 is again vulnerable to CVE-2026-25679.Running this on r7:
returns no findings and no ignored matches. The CPE match for
cpe:2.3:a:golang:go:1.24.13against the DB entrycpe:2.3:a:golang:go:*with constraint< 1.25.8 || >= 1.26.0-0, < 1.26.1is produced by the matcher and then dropped, because the containing APK has a FIXED secfix record at r3 and r7 satisfies>= 2.1.7-r3. Today there is no way for a caller to see that match.This same shape applies to every bundled language package inside any APK that has ever had a FIXED secfix entry.
References
v0.111.0):grype/matcher/internal/distro.go#L105—OwnershipIgnores(... "DistroPackageFixed" ...)call sitegrype/matcher/internal/ignores.go#L12—OwnershipIgnoresfunction definitiongrype/vulnerability_matcher.go#L255-L256—filtered, dropped := match.ApplyIgnoreFilters(...)immediately followed bylogIgnoredMatches(dropped), withdroppednot returnedgrype/vulnerability_matcher.go#L92—FindMatchesContextsignature, the public API affected