Skip to content
folhas.io
secure by design for connected products· Articles

Articles

SBOM for embedded firmware: what the CRA requires and how to generate one without lying

The software bill of materials the CRA demands is not written by hand. For firmware, the only credible SBOM comes out of the build system, and binary scanning serves for what we did not build ourselves.

Published

The Cyber Resilience Act requires, in Annex I, Part II, that the manufacturer identify and document the components of the product, including by means of a machine-readable SBOM covering, at the very least, the top-level dependencies. The SBOM does not have to be public: it forms part of the technical documentation and is handed to the market surveillance authorities on request.

For a web application, this is an afternoon’s work. For firmware, it is where most manufacturers will fail, and fail in a specific way: by delivering an SBOM that looks complete and is not.

The firmware problem

An embedded firmware image typically carries no package manager on board. There is no dpkg or apk database for a scanner to consult. When you point a composition analysis tool at an extracted rootfs, coverage depends on what survived compilation: binary signatures, version banners, strings. The result is large, silent gaps, because the tool does not know what it failed to find.

The practical consequence: an SBOM generated by binary scanning of firmware is a starting point, and it does not suffice as a conformity document.

The rule that solves almost everything

The credible SBOM comes out of the build system, not out of the binary. The build system is the only place that knows exactly what went into the image, with which version, with which patches and under which licence.

The three dominant ecosystems already do this natively:

  • Yocto: the create-spdx class has been included by default via INHERIT_DISTRO since Kirkstone (4.0). A normal image build produces an .spdx.json in the deploy directory, derived from the same inputs that produced the binary. For those who prefer CycloneDX, the meta-cyclonedx meta-layer produces CycloneDX 1.6/1.7 SBOMs with corrected CPE and purl for better matching against the NVD.
  • Buildroot: make legal-info generates the complete manifest of packages, versions and licences; the cyclonedx-buildroot converter turns it into CycloneDX JSON.
  • Zephyr: west spdx generates SPDX 2.3 documents for the application, Zephyr, the build and module dependencies. Mind the documented limitation: vendor binary blobs and out-of-tree libraries are not included; they have to be added as external components or documented as gaps.

And what about what we did not build?

This is where binary analysis has its legitimate place: the bootloader shipped by the SoC vendor, the radio blob, a partner’s pre-compiled library. For those, a binary composition tool produces a document that is then reconciled with the build manifest. The method is two inventories, one of what we control and one of what we inherited, merged into a single document, with the gaps identified as such.

Diagram: the build system generates the SBOM for what we build; the binary scan inventories the inherited components; the two are reconciled into a single final document, with gaps declared.
Two inventories, one document: the build answers for what we built, the scan for what we inherited.

Which format

The two formats accepted in practice are SPDX (the ISO/IEC 5962 standard) and CycloneDX (ECMA-424). The German technical guideline BSI TR-03183-2, the document most cited by auditors and notified bodies in the CRA context, recommends CycloneDX 1.6+ or SPDX 3.0.1+. CycloneDX has a native firmware component type and built-in VEX support, which makes it the natural choice for the CRA workflow; Yocto produces SPDX natively. The pragmatic answer for Yocto users: generate both.

As a reference for minimum content, the US “minimum elements” (updated by CISA in July 2026, superseding the 2021 NTIA version) remain the practical yardstick: supplier, name, version, unique identifier (purl and/or CPE), dependency relationship, SBOM author and date. The field that is worth the most is the version: matching against vulnerabilities is precise to the number. “We use OpenSSL” says nothing; “OpenSSL 3.0.11” says exactly which advisories apply.

What this means for manufacturers

Three decisions we took for our own product, and that we recommend to any team:

  1. The SBOM is a pipeline artefact. It is generated on every tagged build, stored next to the binary, and no human writes or corrects it by hand. If the process requires manual editing, the process is wrong.
  2. The SBOM is only useful wired to monitoring. A static inventory is paper compliance; connected to a CVE tracking tool (Dependency-Track, for example), it becomes the alerting system that feeds the CRA’s own vulnerability handling obligation, and the trigger for the 24h/72h reporting process.
  3. Gaps are declared. A blob we cannot decompose is a line in the SBOM saying so, not an omission. Before a market surveillance authority, a documented gap is a state of affairs; a discovered omission is a different problem.

Sources