Bug 16438

Summary: spdx 3.0.1: Missing internal dependencies: example Go blindspot for CVE scanner
Product: [Build System, Metadata & Runtime] OE-Core Reporter: Robert Berger <pokylinux>
Component: oe-core otherAssignee: Joshua Watt <JPEWhacker>
Status: NEW --- QA Contact:
Severity: normal    
Priority: Medium+ CC: ccasciato, randy.macleod, romain.naour
Version: 6.1   
Target Milestone: 6.2 M2   
Hardware: x86   
OS: Multiple   
Whiteboard:
OS type for building Yocto: --- Type of Regression: ---
Verified: Documentation change: Don't know
Attachments:
Description Flags
spdx, try vuln report, sources none

Description Robert Berger 2026-09-26 09:26:21 UTC
[Bug Summary]
spdx 3.0.1: Missing internal Go module dependencies and stdlib tracking in create-spdx

[Component]
Bitbake / Core Metadata (specifically classes/create-spdx and classes-recipe/go-mod)

[Version]
Yocto 6.0 (Wrynose) / Yocto 6.1 (Blacksail)

[Description]
Starting with Yocto 6.0/6.1, the `create-spdx` architecture introduces native SPDX 3.0.1 JSON-LD output. While it perfectly maps the system-level build topology (linking the recipe to go-cross and go-runtime), there is an architectural visibility gap regarding language-specific inner application dependencies.

When compiling a Go application via `go-mod.bbclass`, the external Go modules defined in `go.mod` (fetched and compiled statically into the binary) are not declared as discrete `software_Package` or `SoftwareMaterial` elements inside the generated package SPDX file (`package-<name>.spdx.json`). The entire source repository context is summarized as a single package entity. 

Consequently, downstream compliance tools and vulnerability scanners parsing the SPDX 3.0.1 graph cannot detect internal application vulnerabilities. The generated Yocto SBOM leaves the application layer completely blank.

[Steps to Reproduce]
1. Create a Go application recipe that fetches external dependencies using `go-mod` (e.g., github.com-robertberger-go-hello).
2. Enable `INHERIT += "create-spdx"` in local.conf.
3. Build the recipe: `bitbake github.com-robertberger-go-hello`.
4. Inspect the generated package SPDX file using jq:
   jq -r '.. | .externalIdentifier?[]? | select(.externalIdentifierType == "purl") | .id' tmp/deploy/spdx/3.0.1/<arch>/packages/package-github.com-robertberger-go-hello.spdx.json

[Actual Results]
The output is completely blank. No `pkg:golang/...` entries exist for the sub-modules or the implicit standard library dependencies, even though they are compiled into the binary.

[Expected Results]
The inner Go module graphs fetched during the build lifecycle should be appended to the package-level SPDX 3.0.1 data stream (similar to how other ecosystems look to leverage `SPDX_PACKAGE_URLS` or macro definitions), providing visibility into statically linked dependencies.

[Example Context]
If you build this[1] go app you see that go.mod pulls in go 1.25.4, which has known vulnerabilities.

[1] https://gitlab.com/meta-layers/meta-yocto-training/-/blob/2026-08-18-training-wrynose-blacksail/recipes-training/golang-helloworld/github.com-robertberger-go-hello_git.bb?ref_type=heads

It looks like those "internal" dependencies do not show up in the SPDX, so the CVE scanner can not detect the CVEs.

With a third party scanner e.g. trivy and some cooking I get this:

## ❤️ Unpatched Vulnerabilities (Combined Audit Scope)
| Audit Scope | Severity | Package | CVE ID | Score | Dep. Type | Linkage | Remediation Action |
| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
| 🎯 TARGET | 🔴 CRITICAL | `stdlib` | **[CVE-2025-68121](https://avd.aquasec.com/nvd/cve-2025-68121)** | 9.5 | GO MOD | **GO (go-hello)** | _UPDATE TO v1.24.13, 1.25.7, 1.26.0-rc.3_ |
| 🎯 TARGET | 😠 HIGH | `stdlib` | **[CVE-2025-61726](https://avd.aquasec.com/nvd/cve-2025-61726)** | 8.0 | GO MOD | **GO (go-hello)** | _UPDATE TO v1.24.12, 1.25.6_ |
| 🎯 TARGET | 😠 HIGH | `stdlib` | **[CVE-2025-61729](https://avd.aquasec.com/nvd/cve-2025-61729)** | 8.0 | GO MOD | **GO (go-hello)** | _UPDATE TO v1.24.11, 1.25.5_ |
| 🎯 TARGET | 😠 HIGH | `stdlib` | **[CVE-2026-25679](https://avd.aquasec.com/nvd/cve-2026-25679)** | 8.0 | GO MOD | **GO (go-hello)** | _UPDATE TO v1.25.8, 1.26.1_ |
| 🎯 TARGET | 😠 HIGH | `stdlib` | **[CVE-2026-27145](https://avd.aquasec.com/nvd/cve-2026-27145)** | 8.0 | GO MOD | **GO (go-hello)** | _UPDATE TO v1.25.11, 1.26.4_ |
| 🎯 TARGET | 😠 HIGH | `stdlib` | **[CVE-2026-32280](https://avd.aquasec.com/nvd/cve-2026-32280)** | 8.0 | GO MOD | **GO (go-hello)** | _UPDATE TO v1.25.9, 1.26.2_ |
| 🎯 TARGET | 😠 HIGH | `stdlib` | **[CVE-2026-32281](https://avd.aquasec.com/nvd/cve-2026-32281)** | 8.0 | GO MOD | **GO (go-hello)** | _UPDATE TO v1.25.9, 1.26.2_ |
| 🎯 TARGET | 😠 HIGH | `stdlib` | **[CVE-2026-32283](https://avd.aquasec.com/nvd/cve-2026-32283)** | 8.0 | GO MOD | **GO (go-hello)** | _UPDATE TO v1.25.9, 1.26.2_ |
| 🎯 TARGET | 😠 HIGH | `stdlib` | **[CVE-2026-33811](https://avd.aquasec.com/nvd/cve-2026-33811)** | 8.0 | GO MOD | **GO (go-hello)** | _UPDATE TO v1.25.10, 1.26.3_ |
| 🎯 TARGET | 😠 HIGH | `stdlib` | **[CVE-2026-33814](https://avd.aquasec.com/nvd/cve-2026-33814)** | 8.0 | GO MOD | **GO (go-hello)** | _UPDATE TO v1.25.10, 1.26.3_ |
| 🎯 TARGET | 😠 HIGH | `stdlib` | **[CVE-2026-33818](https://avd.aquasec.com/nvd/cve-2026-33818)** | 8.0 | GO MOD | **GO (go-hello)** | _UPDATE TO v1.25.13, 1.26.6, 1.27.0-rc.3_ |
| 🎯 TARGET | 😠 HIGH | `stdlib` | **[CVE-2026-39820](https://avd.aquasec.com/nvd/cve-2026-39820)** | 8.0 | GO MOD | **GO (go-hello)** | _UPDATE TO v1.25.10, 1.26.3_ |
| 🎯 TARGET | 😠 HIGH | `stdlib` | **[CVE-2026-39821](https://avd.aquasec.com/nvd/cve-2026-39821)** | 8.0 | GO MOD | **GO (go-hello)** | _UPDATE TO v1.25.13, 1.26.6, 1.27.0-rc.3_ |
| 🎯 TARGET | 😠 HIGH | `stdlib` | **[CVE-2026-39822](https://avd.aquasec.com/nvd/cve-2026-39822)** | 8.0 | GO MOD | **GO (go-hello)** | _UPDATE TO v1.25.12, 1.26.5, 1.27.0-rc.2_ |
| 🎯 TARGET | 😠 HIGH | `stdlib` | **[CVE-2026-39836](https://avd.aquasec.com/nvd/cve-2026-39836)** | 8.0 | GO MOD | **GO (go-hello)** | _UPDATE TO v1.25.10, 1.26.3_ |
| 🎯 TARGET | 😠 HIGH | `stdlib` | **[CVE-2026-42499](https://avd.aquasec.com/nvd/cve-2026-42499)** | 8.0 | GO MOD | **GO (go-hello)** | _UPDATE TO v1.25.10, 1.26.3_ |
| 🎯 TARGET | 😠 HIGH | `stdlib` | **[CVE-2026-42504](https://avd.aquasec.com/nvd/cve-2026-42504)** | 8.0 | GO MOD | **GO (go-hello)** | _UPDATE TO v1.25.11, 1.26.4_ |
| 🎯 TARGET | 😠 HIGH | `stdlib` | **[CVE-2026-56853](https://avd.aquasec.com/nvd/cve-2026-56853)** | 8.0 | GO MOD | **GO (go-hello)** | _UPDATE TO v1.25.13, 1.26.6, 1.27.0-rc.3_ |
| 🎯 TARGET | 😠 HIGH | `stdlib` | **[CVE-2026-56858](https://avd.aquasec.com/nvd/cve-2026-56858)** | 8.0 | GO MOD | **GO (go-hello)** | _UPDATE TO v1.25.13, 1.26.6, 1.27.0-rc.3_ |
| 🎯 TARGET | 😠 HIGH | `stdlib` | **[CVE-2026-56859](https://avd.aquasec.com/nvd/cve-2026-56859)** | 8.0 | GO MOD | **GO (go-hello)** | _UPDATE TO v1.25.13, 1.26.6, 1.27.0-rc.3_ |
| 🎯 TARGET | 😠 HIGH | `stdlib` | **[CVE-2026-56860](https://avd.aquasec.com/nvd/cve-2026-56860)** | 8.0 | GO MOD | **GO (go-hello)** | _UPDATE TO v1.25.13, 1.26.6, 1.27.0-rc.3_ |
| 🎯 TARGET | 😠 HIGH | `stdlib` | **[CVE-2026-56862](https://avd.aquasec.com/nvd/cve-2026-56862)** | 8.0 | GO MOD | **GO (go-hello)** | _UPDATE TO v1.25.13, 1.26.6, 1.27.0-rc.3_ |

The fix is trivial. Just replace go 1.25.4 -> go 1.26.6. But first of all some tool needs to shout that there is an issue to be fixed.

This seems to be an architectural limitation and I'm not sure how this can be fixed system wide.

It also applies to many more use cases like go, rust, npm, python where dependencies are pulled in by the recipe.
Please advise.
Comment 1 Joshua Watt 2026-10-01 14:42:52 UTC
The dependent go modules should be present in the SPDX output as input packages to the build. I believe the thing that is missing is:

1) I'm not sure if these go modules have PURLs assigned to them. I don't know if this is possible to do, but we can investigate that further
2) The PURLs from things in SRC_URI do not automatically propagate down the the packages that are built using those SRC_URIs. We might be able to improve that also
Comment 2 Robert Berger 2026-10-02 10:06:34 UTC
bitbake virtual/robertberger-go-hello -c sbom_cve_check_recipe

returns this:

WARNING: github.com-robertberger-go-hello-vuln-git-r0 do_sbom_cve_check_recipe: binutils-cross-aarch64-2.47: Found unpatched CVEs: CVE-2026-3441, CVE-2026-3442, CVE-2026-6844, CVE-2026-6845, CVE-2026-90801, CVE-2026-90802, CVE-2026-90803, CVE-2026-90804, CVE-2026-90828, CVE-2026-90829, CVE-2026-90830, CVE-2026-90831, CVE-2026-91779, CVE-2026-91780, CVE-2026-91781, CVE-2026-91782
WARNING: github.com-robertberger-go-hello-vuln-git-r0 do_sbom_cve_check_recipe: bison-native-3.8.2: Found unpatched CVEs: CVE-2026-56390
WARNING: github.com-robertberger-go-hello-vuln-git-r0 do_sbom_cve_check_recipe: glibc-2.44+git: Found unpatched CVEs: CVE-2026-18374, CVE-2026-19499, CVE-2026-19542, CVE-2026-77117, CVE-2026-80489, CVE-2026-8674, CVE-2026-86805, CVE-2026-89092, CVE-2026-95818, CVE-2026-97399
WARNING: github.com-robertberger-go-hello-vuln-git-r0 do_sbom_cve_check_recipe: popt-native-1.19: Found unpatched CVEs: CVE-2026-18739, CVE-2026-18743, CVE-2026-18839
WARNING: github.com-robertberger-go-hello-vuln-git-r0 do_sbom_cve_check_recipe: zlib-native-1.3.2: Found unpatched CVEs: CVE-2026-76844, CVE-2026-85091

which means it does not care about the go version used.

trivy scan returns a lot of CVEs due to the go version and the go stdlib.

tree github.com-robertberger-go-hello-vuln
github.com-robertberger-go-hello-vuln
├── aarch64
│   ├── builds
│   │   └── build-github.com-robertberger-go-hello-vuln.spdx.json
│   ├── common-package
│   │   └── github.com-robertberger-go-hello-vuln-package-common.spdx.json
│   ├── packages
│   │   ├── package-github.com-robertberger-go-hello-vuln-dbg.spdx.json
│   │   ├── package-github.com-robertberger-go-hello-vuln-dev.spdx.json
│   │   └── package-github.com-robertberger-go-hello-vuln.spdx.json
│   ├── packages-staging
│   │   ├── package-github.com-robertberger-go-hello-vuln-dbg.spdx.json
│   │   ├── package-github.com-robertberger-go-hello-vuln-dev.spdx.json
│   │   └── package-github.com-robertberger-go-hello-vuln.spdx.json
│   └── static
│       └── static-github.com-robertberger-go-hello-vuln.spdx.json
├── src
│   ├── go.mod
│   ├── main.go
│   └── readme.txt
└── trivy-scan
    └── github.com-robertberger-go-hello-vuln-src-vuln.json


under aarch64: our generated spdx
under src: what trivy uses for scanning
under trivy-scan: the output of the scan

I'll attach a tarball with this info.
Comment 3 Robert Berger 2026-10-02 10:08:12 UTC
Created attachment 5251 [details]
spdx, try vuln report, sources

Maybe this helps?
Comment 4 Romain Naour 2026-10-08 14:38:06 UTC
Hello,

Thanks for the detailed report!

I noticed a similar issue for a custom npm package using a npm-shrinkwrap.json (npmsw fetcher).

The generated SPDX 3.0.1 sbom doesn't list any dependencies listed in the npm-shrinkwrap.json while external sbom tool (cdxgen) list several vulnerabilities.

The sbom only contains the "software_packageUrl": "pkg:npm/<custom_pkg>" for the main custom package. But there is no `pkg:npm/...` entries related to the "sub-module" list of npm packages from npm-shrinkwrap.json.

I'm agree with the analysis:

"It also applies to many more use cases like go, rust, npm, python where dependencies are pulled in by the recipe."

Also, when a vulnerability for such "sub-module" is added to the SBOM, the sbom-cve-check should be able to know if it has been fixed or not. How to distinguish a patch fixing a CVE for a "sub-module" or the main package?

Best regards,
Romain
Comment 5 Robert Berger 2026-10-08 16:41:46 UTC
@Romain Naour:

I think npm shrinkwrap is disabled in recent Yocto versions due to security concerns.
Nevertheless you can still use the standard fetcher to use npm packages with "internal dependencies" which are not seen by the current design of OE/YP.

One solution I am playing with is to use use a 3rd party scanner like trivy and let it run over parts of the sources (lock files,...). It looks like this can detect such issues.

If you want to play with my bbclass I can send it over. It's not yet in my public layers. It will eventually be here[1]

[1] https://gitlab.com/meta-layers/meta-resy/-/tree/master/classes?ref_type=heads