The problem: A server-side SBOM generator expects a package manager and a lockfile. Your device ships a cross-compiled image, a bootloader, a vendor radio module and no package manager at runtime.
Why firmware SBOMs are different
- Static linking hides dependencies inside a binary; there is no runtime package list to inspect.
- Build systems (Buildroot, Yocto, Zephyr, vendor SDKs) already know the recipe versions — the SBOM should be an output of that build, not a separate archaeology project.
- A meaningful share of the image is vendor blobs with no public package identity at all.
- The same source library may be patched by the vendor, so the upstream version alone is not the whole truth.
- The artifact you ship is a firmware image with its own hash, not a directory of files.
What to include
| Field | Why it matters | Typical mistake |
|---|---|---|
| metadata.component = the firmware | Anchors the SBOM to a product and version | Listing only components, with no product identity |
| Component name, version, supplier | Minimum identity for any matching or support answer | Supplier set to “unknown” for every entry |
| purl or CPE | The only reliable way to match advisories | Descriptive versions that cannot be resolved |
| Nested components | Statically linked libraries inside dependencies | Only top-level dependencies declared |
| Dependency relationships | Explains which component pulled in which | References that do not resolve to a component |
| Hashes and licenses | Integrity and obligation review | Hashes of the SBOM instead of the components |
| Build metadata | Reproducibility and provenance | No tool name or build timestamp |
Generate it from the build
- Yocto: use the SPDX or CycloneDX generation class in your image recipe and publish the document as a release artifact.
- Buildroot: collect the legal-info manifests the build already produces and convert them to CycloneDX or SPDX in a post-build step.
- Zephyr or vendor SDKs: add an explicit manifest step that lists modules with their versions and commit identifiers.
- Always set the firmware product and version in metadata, and attach the firmware image hash.
Treat SBOM generation as a build gate. If the document is produced by hand after the release, it will describe the release someone remembers rather than the one that shipped.
Validate in CI, with the same limits as production
Validation must fail the build on the defects you care about: unsupported format versions, components with no identity, dependency references that do not resolve, and an implausible component count. Everything else should be a warning with an owner.
- format is CycloneDX 1.4+ or SPDX 2.3 JSON
- schema validation passes
- component count >= the previous release's count - expected removals
- zero components without purl, CPE or an explicit vendor-component marker
- zero broken dependency references
- firmware image hash present in metadataWhat an SBOM still will not tell you
An SBOM describes declared software, not the binary reality of the image. If a component was linked in without appearing in the build manifest, the SBOM will not contain it. Binary analysis answers a different question; neither replaces the other.
The same applies to configuration: a vulnerable library that is compiled without the affected code path is still listed, and an SBOM cannot tell you whether the device is exploitable.
Scope and limits
- This guide does not replace your build system's documentation or a binary analysis of the image.
- A complete SBOM is a prerequisite for CRA evidence, not evidence of compliance.