You need both: a Yocto Project or Buildroot build-time SBOM is the most accurate record of what your recipes and packages compiled, with exact versions, licences and applied CVE patches, while a scan of the finished firmware image is the only check of what actually shipped, including prebuilt vendor binaries, files copied in by post-build scripts and components the build metadata misdeclares. Treat the build SBOM as the primary record you publish and the image scan as the independent cross-check you run before every release.
Key takeaways
- An SBOM is only as good as the place it was recorded.
- The defaults are a starting point.
- make show-info prints a JSON description of the enabled packages "together with their dependencies, licenses and other metadata"; piping it into utils/generate-cyclonedx produces a CycloneDX SBOM.
- Both build systems describe what their recipes declare.
Why does it matter where an SBOM was generated?
An SBOM is only as good as the place it was recorded. NTIA's Minimum Elements for a Software Bill of Materials names three points where component data can be collected: "from the software source, at build time, or after build through a binary analysis tool", and warns that "the SBOM may have some differences depending on when and where the data was created". The same report asks SBOM authors to state "known unknowns" explicitly, so a consumer can tell a component with no further dependencies from one whose dependencies were simply not enumerated. The baseline fields themselves (supplier, component name, version, unique identifiers, dependency relationship, author, timestamp) are covered in our SBOM minimum elements guide.
For embedded Linux this choice is concrete. The build system sees every recipe, its upstream version and every patch applied to it, which a binary scanner can only infer. The finished image contains every file that actually ships, including files that never passed through a recipe. Each view has blind spots the other one covers.
How do you generate an SBOM with the Yocto Project?
The Yocto Project Development Tasks Manual states that the OpenEmbedded build system generates an SBOM "by default (by inheriting the create-spdx class in INHERIT_DISTRO)", describing "all the components you used, their licenses, their dependencies, their sources, the changes that were applied to them and the known vulnerabilities that were fixed". Building an image writes IMAGE-MACHINE.spdx.json to tmp/deploy/images/MACHINE/, and bitbake <recipe> -c create_recipe_sbom produces one from recipe metadata alone. The output is SPDX, the format the SPDX project describes as "recognized as the international open standard for security, license compliance, and other software supply chain artifacts as ISO/IEC 5962:2021"; on the Scarthgap 5.0 LTS release SPDX 3.0 output is off by default and is switched on by replacing create-spdx with create-spdx-3.0 in INHERIT_DISTRO. Our SPDX 3.0 specification guide covers what changed in that format version.
The defaults are a starting point. Variables add the detail that matters for security review:
| Variable | What it adds to the Yocto SPDX output |
|---|---|
SPDX_INCLUDE_SOURCES |
A description of the source files used to build host tools and target packages |
SPDX_INCLUDE_KERNEL_CONFIG |
The Linux kernel CONFIG_* parameters, so a kernel CVE can be checked against the options actually enabled |
SPDX_INCLUDE_PACKAGECONFIG |
Each recipe's enabled and disabled PACKAGECONFIG features |
SPDX_IMAGE_SUPPLIER, SPDX_PACKAGE_SUPPLIER |
Supplier information, one of NTIA's minimum elements |
For vulnerabilities, the Scarthgap Checking for Vulnerabilities chapter enables the cve-check class with INHERIT += "cve-check", which maps "each compiled software component recipe name and version information to the CVE database" and writes per-recipe reports to tmp/deploy/cve. The current Yocto Project Security Manual describes its successor, sbom-cve-check, enabled with the core/yocto/sbom-cve-check configuration fragment, which writes an image-level report plus an SPDX file enriched with the same CVE data. Both give every matched CVE one of three statuses: Patched, Unpatched or Ignored. Two details decide whether those statuses are right. A backported fix counts as Patched only when its patch header carries a CVE: tag. When a recipe name does not match the CVE database's product name, CVE_PRODUCT (for example "flex_project:flex westes:flex") corrects the mapping in both directions.
How do you generate an SBOM with Buildroot?
The Buildroot user manual splits the job across several make targets rather than one SBOM class:
make legal-infocollects licence-compliance material underlegal-info/: the Buildroot configuration, package sources, the patches that were applied, licence texts, and "a manifest file (one for host and one for target packages) listing the configured packages, their version, license and related information". Items Buildroot cannot determine are marked "unknown".make show-infoprints a JSON description of the enabled packages "together with their dependencies, licenses and other metadata"; piping it intoutils/generate-cyclonedxproduces a CycloneDX SBOM. Our CycloneDX vs SPDX guide compares the two formats.make pkg-statsproduces HTML and JSON output including "whether known CVEs (security vulnerabilities) affect the packages in your current configuration" and whether a newer upstream version exists.
Per-package metadata drives the matching. LIBFOO_CPE_ID_* variables set each package's CPE identifier, with the vendor defaulting to <pkgname>_project. LIBFOO_IGNORE_CVES records CVEs that a patch fixes or that do not apply to Buildroot's build of the package, and the manual requires a Makefile comment explaining each one. The manual is also direct about the limits of legal-info: its output "is based on declarative statements in each of the packages recipes", and those statements may not be "fully accurate nor exhaustive", so it must be checked before you rely on it.
What does a build-system SBOM miss that an image scan catches?
Both build systems describe what their recipes declare. Anything that reaches the image without a recipe, or with wrong recipe metadata, is invisible to them:
| Gap | Why the build SBOM misses it | What the image scan sees |
|---|---|---|
| Prebuilt vendor binaries (Wi-Fi firmware, GPU or modem userspace, SDK libraries) | Installed as opaque files; the recipe declares the package, not the open-source libraries compiled inside it | Version strings and signatures of the components inside the binary |
| Files added by overlays or post-build scripts | Buildroot rootfs overlays and post-build scripts, or a Yocto ROOTFS_POSTPROCESS_COMMAND, copy files after package metadata is recorded |
Every file present in the final filesystem |
| Statically linked or vendored code | The recipe lists the top-level package, not a library copied into its source tree | Embedded library versions inside the executable |
| Wrong name or version mapping | A recipe name that does not match the CVE product, or a version string the database does not recognise, produces a false negative | An independent identification to compare against |
| Partitions outside the root filesystem | Bootloader, trusted firmware or a separately built kernel may come from another toolchain | All partitions in the flashed image, including the bootloader (see our U-Boot bootloader security guide) |
The reverse is also true. A binary scan cannot see a backported patch the way the build system does: a scanner that reads OpenSSL's version string may flag CVEs your recipe already fixed with a CVE:-tagged patch. That is why the build SBOM remains the primary record, and why the build system's Patched and Ignored statuses (with the reason recorded) are the evidence that closes such a finding. Publishing those decisions as VEX is covered in our CSAF and VEX for device makers guide.
When do you need both, and how do you reconcile them?
You need both whenever the image contains anything not built from your own layers or packages, which for most commercial embedded Linux products means always: board support packages, vendor blobs and post-build steps are the norm. A workable release step:
- Generate the build SBOM and CVE report on every release build (
create-spdxpluscve-checkorsbom-cve-checkon Yocto;show-infowithgenerate-cyclonedx,pkg-statsandlegal-infoon Buildroot) and keep them with the release artefacts. - Scan the exact image file you flash or ship, not an intermediate rootfs, and produce an image-derived SBOM.
- Diff the two by component name and version. Anything in the image scan but missing from the build SBOM is a component to add, with its supplier. Anything with different versions needs a decision: a backport, a misdeclared version or a stale package.
- Prioritise the remaining open CVEs by exploitation evidence rather than CVSS alone, as our KEV and EPSS prioritisation guide describes, and record each "not affected" decision with its reason.
Our firmware SBOM guide covers the image side of this process when no build-system SBOM exists at all, such as for third-party modules you integrate but do not build.
AI-assisted analysis: what SoftWSP actually runs
SoftWSP works on the finished image, the second half of the comparison above. The pipeline unpacks a firmware image, identifies the software components and versions present in its binaries, and matches each component version against public CVE records, CISA's Known Exploited Vulnerabilities catalog and FIRST EPSS scores. The matching and scoring are deterministic code. AI's role is narration: it writes the plain-language summary of which components were found, which CVEs match and which are KEV-listed or high-EPSS, with each statement citing the component, version and record behind it. An engineer reviews every finding before the report ships. Code scores, AI narrates.
The service report carries the image-derived SBOM, one per firmware version, which sits beside your Yocto or Buildroot SBOM. Our free SBOM diff tool runs in your browser and lists added, removed, version-changed and licence-changed components between any two CycloneDX or SPDX 2.x JSON SBOMs, such as two consecutive release builds. Deciding why a difference exists, such as whether a version mismatch is a backported fix your cve-check report already marks Patched, stays with your engineers. SoftWSP does not read your build tree, layers or recipes.
This guide draws on the Yocto Project Development Tasks Manual and Security Manual (current and Scarthgap 5.0), the Buildroot user manual, NTIA's Minimum Elements for an SBOM and the SPDX project's overview, read directly 2026-11-10.
Put this guide to work
Frequently asked questions
Is the SBOM from Yocto or Buildroot enough on its own for a firmware release?
It is the most accurate record of what the build system compiled, but it is not a complete record of what ships. A Yocto Project or Buildroot SBOM is generated from recipe and package metadata, so it is exact for every component the build system built from source, with the version, licence and applied patches it actually used. It cannot see what never passed through a recipe: a vendor's prebuilt binary or kernel module copied in by an overlay or post-build script, a statically linked library the recipe metadata does not declare, or a component whose declared name and version are wrong. Scanning the finished firmware image is the independent check that catches those gaps before the image reaches a customer.
How do you generate an SBOM with the Yocto Project?
The Yocto Project's Development Tasks Manual states that the OpenEmbedded build system generates an SPDX SBOM by default, by inheriting the create-spdx class in INHERIT_DISTRO. Building an image writes an IMAGE-MACHINE.spdx.json file to tmp/deploy/images/MACHINE/ in the Build Directory, and bitbake <recipe> -c create_recipe_sbom produces one from recipe metadata only. On the Scarthgap (5.0) LTS release, SPDX 3.0 output is available but off by default; it is enabled by swapping create-spdx for create-spdx-3.0 in INHERIT_DISTRO. Variables such as SPDX_INCLUDE_SOURCES, SPDX_INCLUDE_KERNEL_CONFIG and SPDX_PACKAGE_SUPPLIER add source files, kernel configuration and supplier data to the document.
What is the difference between Yocto cve-check and sbom-cve-check?
Both map each compiled recipe's name and version to the CVE database at build time and give every matched CVE a status of Patched, Unpatched or Ignored. On Scarthgap (5.0) the check is the cve-check class, enabled with INHERIT += "cve-check", which writes per-recipe JSON reports to tmp/deploy/cve. The current Yocto Project Security Manual describes the sbom-cve-check class, enabled with the core/yocto/sbom-cve-check configuration fragment, which writes an image-level report and an SPDX file enriched with the same CVE data to the image deploy directory. In both, a patch counts as Patched only if its header carries a CVE: tag, and CVE_PRODUCT fixes recipe names that do not match the CVE database's product names.
What do Buildroot's legal-info and pkg-stats targets produce?
make legal-info collects licence-compliance material under output/legal-info/: the Buildroot configuration, package sources, applied patches, license texts and a manifest of configured packages with their version and licence, marking undefined items as "unknown". make show-info prints JSON describing every enabled package with its dependencies and licences, and piping it into utils/generate-cyclonedx produces a CycloneDX SBOM. make pkg-stats produces HTML and JSON reports showing, among other details, whether known CVEs affect the packages in the current configuration and whether a newer upstream version exists. The Buildroot manual itself warns that legal-info output is built from each recipe's declarative statements and must be checked before use.
Can SoftWSP compare a Yocto or Buildroot SBOM against the shipped firmware image?
SoftWSP scans the finished firmware image: it unpacks it, identifies the software components and versions present in the binaries, and matches each one against CVE records, CISA's Known Exploited Vulnerabilities catalog and FIRST EPSS scores, with AI writing the plain-language summary an engineer reviews before the report ships. The report carries that image-derived SBOM, one per firmware version, to set beside your build-system SBOM; SoftWSP's free in-browser SBOM diff tool shows the added, removed and version-changed components between any two CycloneDX or SPDX 2.x JSON SBOMs. Reconciling each difference, such as deciding whether a version mismatch is a backported fix, stays an engineering judgement.
Sources
- Yocto Project Development Tasks Manual: Creating a Software Bill of Materials
- Yocto Project Security Manual: Checking for Vulnerabilities (sbom-cve-check)
- Yocto Project 5.0 (Scarthgap) Development Tasks Manual: Checking for Vulnerabilities (cve-check)
- The Buildroot user manual (legal-info, show-info, pkg-stats, CycloneDX SBOM)
- NTIA: The Minimum Elements For a Software Bill of Materials (SBOM), July 12, 2021
- SPDX project: About SPDX (ISO/IEC 5962:2021)
About this guide
SoftWSP Firmware Security Desk
Covers the Firmware vulnerabilities & fixes cluster: 102 guides.

In this cluster
Questions about this page?
