fix(matcher/golang): surface advisories pinned at import-path granularity (#3398)#3424
Open
ChrisJr404 wants to merge 1 commit into
Open
Conversation
…rity
Go advisories are routinely filed against an import path inside a larger
module (e.g. "golang.org/x/crypto/ssh"), while Go binaries only carry
module-granularity build info via debug/buildinfo. Syft therefore emits
the module ("golang.org/x/crypto") and the matcher's case-insensitive
exact-name lookup never lands on advisories pinned to subpaths.
Recent in-the-wild instance: GHSA-mh2q-q3fh-2475 / CVE-2026-29181 was
originally pinned at "go.opentelemetry.io/otel/baggage" and
"go.opentelemetry.io/otel/propagation". Binaries linking
"go.opentelemetry.io/otel" v1.40.0 produced no findings until the
advisory was manually amended to also list the parent module. Same
pattern resurfaces every time an advisory uses an import-path name.
This change supplements the existing exact-name match with a
prefix search keyed on p.Name + "/", so an SBOM module also
surfaces advisories whose package name is a path-segment-bounded sub-path
of it. The "/" boundary prevents an unrelated module that shares only a
name prefix substring (e.g. "golang.org/x/cryptographer" vs
"golang.org/x/crypto") from matching.
Implementation:
- New ByPackageNamePrefix criterion enforces the path-segment boundary
in MatchesVulnerability.
- PackageSpecifier gains a NamePrefix field; v6 store translates it into
a parameterized "packages.name LIKE ? ESCAPE '\\'" query with wildcard
metacharacters in the prefix neutralized.
- Go matcher invokes the prefix path only when p.Type is GoModulePkg and
the name has at least one "/", to avoid fanning out the synthetic
"stdlib" entry or single-segment names across the corpus.
- The version, qualified-package, and unaffected-nak pipeline is reused
unchanged via a shared internal helper, so prefix-matched advisories
participate in version filtering and ignore-rule construction the same
way exact-matched ones do.
The trade-off (over-reporting for binaries that don't import a vulnerable
sub-package of a module they depend on) is the desired direction for a
vulnerability scanner; downstream reachability triage is left to tools
like govulncheck.
Closes anchore#3398
Signed-off-by: ChrisJr404 <chris@hacknow.com>
kzantow
reviewed
May 8, 2026
kzantow
left a comment
Contributor
There was a problem hiding this comment.
The example in the issue indicates this was a data problem that has now been fixed. Are there other examples that show we should actually make a change here?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #3398.
What
The Go matcher silently drops advisories pinned at an import path inside a larger module. Go binaries only retain module-granularity build info via `debug/buildinfo`, so syft emits the module (`golang.org/x/crypto`) but the advisory's package name (`golang.org/x/crypto/ssh`) is what GitHub Advisories / OSV record. The matcher's case-insensitive exact-name lookup never lands.
The issue calls out GHSA-mh2q-q3fh-2475 / CVE-2026-29181 as a recent example: pinned at `go.opentelemetry.io/otel/baggage` and `/propagation`, missed by grype against binaries linking `go.opentelemetry.io/otel` v1.40.0 until the advisory was manually amended to also list the parent module. Every future advisory filed at import-path granularity hits the same wall.
Fix
The Go matcher now supplements the existing exact-name lookup with a prefix-search keyed on the SBOM package name plus a `/` segment break. So when the SBOM has `golang.org/x/crypto`, advisories pinned at `golang.org/x/crypto/ssh` (or any deeper sub-path) surface alongside ones pinned at the module name itself.
Path-segment safety: the prefix is `p.Name + "/"`, not just `p.Name`. `golang.org/x/crypto` matches `golang.org/x/crypto/ssh` but does NOT match `golang.org/x/cryptographer`. The `/` is enforced in two places: the SQL `LIKE` pattern, and the criterion's `MatchesVulnerability` (defense-in-depth). LIKE wildcards in the prefix are neutralized via SQLite `ESCAPE` clause.
The prefix path runs only when:
Both conditions together prevent the synthetic `stdlib` entry or other single-segment names from fanning out across the entire Go advisory corpus.
The trade-off (over-reporting when a binary doesn't import a vulnerable sub-package of a module it depends on) is called out in the issue and is the desired direction for a vulnerability scanner; downstream reachability triage belongs to tools like govulncheck.
Implementation notes
Test plan