Skip to content

fix(vex): avoid panic on CSAF relationships without a sub-component - #11067

Open
ashvinctrl wants to merge 1 commit into
aquasecurity:mainfrom
ashvinctrl:fix/vex-csaf-nil-subcomponent
Open

fix(vex): avoid panic on CSAF relationships without a sub-component#11067
ashvinctrl wants to merge 1 commit into
aquasecurity:mainfrom
ashvinctrl:fix/vex-csaf-nil-subcomponent

Conversation

@ashvinctrl

Copy link
Copy Markdown

Description

Scanning with a CSAF VEX document crashes with a nil pointer panic when the document declares a relationship and the vulnerability is detected on the product that relationship relates to.

reachRoot evaluates the leaf component on its own before walking up to the root, and passes a nil sub-component:

// pkg/vex/vex.go
if notAffected(leaf, nil) {
	return false
}

matchRelationship dereferenced that argument without a check:

// pkg/vex/csaf.go
if subProductPURL.Match(subProduct.PkgIdentifier.PURL) {

So as soon as a relationship's relates_to_product_reference resolves to a PURL that matches a vulnerable component, the scan segfaults. OpenVEX.Matches already guards the same argument; CSAF did not.

A relationship describes a sub-component within a product, so it cannot match when no sub-component is given. This returns early in that case, which leaves the existing matching behaviour untouched.

The panic aborts the whole scan with exit code 2, and crashes programs that embed Trivy as a library.

There is no associated issue. The fix is small and self-contained, so per the contributing guide I'm including the justification here instead.

Reproduction

A CycloneDX SBOM with github.com/gogo/protobuf@v1.3.1 (CVE-2021-3121) and a child component, plus a CSAF document that puts the child inside protobuf:

"relationships": [
  {
    "category": "default_component_of",
    "product_reference": "leaf-v0.1.0",
    "relates_to_product_reference": "protobuf-v1.3.1",
    "full_product_name": {
      "product_id": "protobuf-v1.3.1-leaf-v0.1.0",
      "name": "leaf as a component of protobuf"
    }
  }
],
"vulnerabilities": [
  {
    "cve": "CVE-2021-3121",
    "product_status": {
      "known_not_affected": ["protobuf-v1.3.1-leaf-v0.1.0"]
    }
  }
]

Before

$ trivy sbom sbom.json --scanners vuln --vex csaf-vex.json
2026-08-10T22:26:52+05:30	INFO	[gobinary] Detecting vulnerabilities...
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0xb0]

goroutine 1 [running]:
github.com/aquasecurity/trivy/pkg/vex.(*CSAF).matchRelationship(...)
	pkg/vex/csaf.go:101
github.com/aquasecurity/trivy/pkg/vex.(*CSAF).match(...)
	pkg/vex/csaf.go:73
github.com/aquasecurity/trivy/pkg/vex.(*CSAF).NotAffected(...)
	pkg/vex/csaf.go:44
github.com/aquasecurity/trivy/pkg/vex.(*Client).NotAffected(...)
	pkg/vex/vex.go:141
github.com/aquasecurity/trivy/pkg/vex.reachRoot(...)
	pkg/vex/vex.go:181
github.com/aquasecurity/trivy/pkg/vex.filterVulnerabilities(...)
	pkg/vex/vex.go:153
...
$ echo $?
2

After

The scan completes, and the vulnerability on protobuf is still reported, since the statement covers the child as a component of protobuf and not protobuf itself:

$ trivy sbom sbom.json --scanners vuln --vex csaf-vex.json
 (gobinary)
===========
Total: 1 (HIGH: 1, CRITICAL: 0)

┌──────────────────────────┬───────────────┬──────────┬────────┬───────────────────┬───────────────┐
│         Library          │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │
├──────────────────────────┼───────────────┼──────────┼────────┼───────────────────┼───────────────┤
│ github.com/gogo/protobuf │ CVE-2021-3121 │ HIGH     │ fixed  │ v1.3.1            │ 1.3.2         │
└──────────────────────────┴───────────────┴──────────┴────────┴───────────────────┴───────────────┘
$ echo $?
0

Relationship filtering itself is unchanged. With the same SBOM shape inverted, so that protobuf is the sub-component of a parent module, the statement still suppresses the finding:

$ trivy sbom sbom2.json --scanners vuln --vex csaf-vex2.json
INFO	[vex] Filtered out the detected vulnerability	format="CSAF" vulnerability-id="CVE-2021-3121" product-id="parent-v0.1.0-protobuf-v1.3.1" status="not_affected" relationship="default_component_of"

Related issues

N/A

Checklist

  • I've read the guidelines for contributing to this repository.
  • I've followed the conventions in the PR title.
  • I've added tests that prove my fix is effective or that my feature works.
  • I've updated the documentation with the relevant information (not needed).
  • I've added usage information (no new options).
  • I've included a "before" and "after" example to the description (included above).

reachRoot evaluates the leaf component on its own before walking up to
the root, passing a nil sub-component. matchRelationship dereferenced it
unconditionally, so a CSAF document whose relationship relates to a
component that is itself vulnerable crashed the scan.

A relationship describes a sub-component within a product, so it cannot
match when no sub-component is given.
@CLAassistant

CLAassistant commented Aug 10, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants