Chen Embedded Software · Article · October 2026

How to generate an SBOM for an STM32CubeIDE project (EU Cyber Resilience Act)

For firmware engineers shipping STM32-based products into the EU. About 8 minutes; the commands take about 5.

Since 11 September 2026, manufacturers selling connected products in the EU must report actively exploited vulnerabilities in those products to ENISA, starting with an early warning within 24 hours. From 11 December 2027, a machine-readable software bill of materials (SBOM) becomes part of the mandatory technical documentation. Both obligations come from the Cyber Resilience Act (Regulation (EU) 2024/2847).

In practice, you can't meet a 24-hour clock unless you already know which libraries and versions are in each firmware image. That's what an SBOM is for. And for a typical STM32 project, generating one is harder than it should be.

Why the usual SBOM tools find nothing

Tools like Syft and Trivy work by reading package-manager metadata: package-lock.json, go.sum, Debian package databases. A CubeIDE or Makefile project has none. FreeRTOS, Mbed TLS, lwIP, FatFs, the HAL drivers and the USB library are copied into the source tree by CubeMX or by hand. Scan the folder and you typically get an empty SBOM. Hand-write one and vulnerability scanners still miss things unless every component has exactly the right CPE identifier.

There is a second problem: what's in the tree is not what ships. With --gc-sections, the linker discards whole libraries you never call. An SBOM listing everything in Middlewares/ overstates your exposure and creates false alarms.

Step 1: Make sure your build produces a map file

STM32CubeIDE writes a linker map by default: after a build, look for Debug/<ProjectName>.map (or Release/). For a Makefile or CMake build, add this to your link flags:

-Wl,-Map=build/firmware.map

The map file records every object file that contributed code or data to the final image. We'll use it to keep only components that actually ship.

Step 2: Generate the SBOM

fwsbom is a free, open-source (Apache-2.0) tool built for this case. It reads the version numbers from the vendored sources themselves (for example tskKERNEL_VERSION_NUMBER in FreeRTOS, MBEDTLS_VERSION_STRING, or the HAL's __STM32F4xx_HAL_VERSION macros) and the STM32Cube firmware package version from your .ioc file. It then checks the map file.

pip install fwsbom
cd path/to/your/project
python -m fwsbom . --map Debug/MyProject.map --linked-only \
    --name my-device --version 1.4.0 --supplier "My Company" \
    --summary -o sbom.cdx.json

Example output (illustrative project):

COMPONENT                    VERSION        LINKED  EVIDENCE
CMSIS-Core                   5.6            ?       Drivers/CMSIS/Core/Include/cmsis_version.h
FreeRTOS-Kernel              10.3.1         yes     Middlewares/Third_Party/FreeRTOS/Source/include/task.h
STM32 USB Device Library     2.11.3         ?       Middlewares/ST/STM32_USB_Device_Library/...
STM32Cube FW_L4              1.18.1         ?       MyProject.ioc
STM32L4xx HAL Driver         1.13.4         yes     Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal.c
LINKEDMeaning
yesAt least one of the component's object files is in the image
noPresent in the tree but nothing reached the image; dropped with --linked-only
?Header-only, a package-level entry, or no map supplied

The result is a CycloneDX 1.5 JSON file. Each component carries a package URL, plus a CPE where the US National Vulnerability Database has one; fwsbom's CPEs are checked against the NVD dictionary.

Step 3: Check it for known vulnerabilities

Feed the SBOM to Grype (on Windows: winget install Anchore.Grype):

grype sbom:sbom.cdx.json

Grype lists every matching CVE, with severity, the fixed version, an EPSS exploit-probability score, and whether the CVE is in CISA's Known Exploited Vulnerabilities catalog. That last column matters most under the CRA: an actively exploited vulnerability in your product is what triggers the 24-hour report.

As a reference point, an SBOM for a project with FreeRTOS 10.0.1, Mbed TLS 2.16.0, lwIP 2.1.2, FatFs R0.12 and cJSON 1.7.12 produces 57 matches. Old vendored libraries are where most firmware exposure hides.

Step 4: Triage before you panic

A match means the version is affected, not necessarily your product. For each High or Critical finding, ask:

Write the reasoning down. If a regulator or customer asks why a CVE didn't require action, that note is your answer.

Step 5: Keep it current automatically

An SBOM is a snapshot, but new CVEs are published against old code every week. Two habits cover it:

  1. Generate the SBOM in CI on every release build and archive it with the release. You'll need it for the technical documentation from December 2027.
  2. Re-scan every night, even when the code hasn't changed. A new failure on unchanged firmware means a new CVE affects products already in the field.

Need the policies and pipeline ready-made? The CRA Firmware Readiness Kit includes GitHub Actions and GitLab CI templates for exactly this pipeline, plus a vulnerability-handling policy, a disclosure policy and pre-filled ENISA 24 h / 72 h / final report templates. Prefer not to run it yourself? SBOM Watch monitors your SBOMs daily and emails you when a component becomes actively exploited.

Common questions

Doesn't ST already publish an SBOM? Recent STM32Cube firmware packages include a CycloneDX sbom_cdx.json describing the components in the package. ST notes it is a reference and does not replace your own project SBOM. Your firmware uses a subset of the package, plus your own third-party code.

Do I need an SBOM before December 2027? The formal requirement applies from 11 Dec 2027. The reporting duty is already in force, though, and without an SBOM you can't reliably tell within 24 hours whether a newly exploited CVE affects you.

What about Zephyr or ESP-IDF? Both have their own SBOM tooling (west spdx, esp-idf-sbom). fwsbom targets the bare-metal and RTOS projects that have none.