SBOM tooling for embedded systems: Syft, Trivy, Yocto SPDX and CycloneDX-generators compared
SBOM tools for embedded development compared — Syft, Trivy, Yocto create-spdx, CycloneDX-generators, EMBA — with a decision matrix and CRA Annex I Part II mapping.
By Vladimír Vician
The Cyber Resilience Act (Regulation (EU) 2024/2847) ties a manufacturer's vulnerability handling obligation to the existence of an accurate, machine-readable SBOM. Annex I Part II requires manufacturers to identify and document vulnerabilities and components contained in the product, and the Commission's CRA policy page treats the SBOM as the operational backbone of that duty. For embedded teams the practical question is which tools to actually run — and which combination produces an SBOM that survives a market surveillance request.
This article compares the major SBOM toolchains for embedded development across two axes: build-time generation versus binary scanning, and SPDX versus CycloneDX format support. It pairs each tool with its honest limitations and maps each option to the CRA Annex I Part II requirement language. For cadence rules see our SBOM update frequency guide; for the format-level choice see CycloneDX vs SPDX for hardware; for the harder case of legacy binaries see the companion article on SBOM from legacy embedded firmware.
Two workflows that fit different teams
The fundamental decision is whether your SBOM comes from the build or from the binary.
Build-time SBOM is generated by the same toolchain that produces the firmware artifact. The build system already knows every recipe, every source URL, every patch applied, every license and every version. The SBOM is exact, the manifest is complete, and the generation runs in CI alongside compilation. This is the gold standard. Yocto's create-spdx class, Buildroot's manifest export and language-specific CycloneDX generators (cyclonedx-python, cyclonedx-node-npm, cyclonedx-go) all sit in this category.
Binary-scan SBOM is generated by analysing the produced binary or its packaged form. The scanner reads package-manager databases (apk, dpkg, RPM) inside container or root filesystems, inspects language-specific manifests (composer.lock, package-lock.json, go.sum, requirements.txt) found in source trees, and uses heuristics for stripped binaries. The output is inferred — accurate for what the scanner can see, silent on what it cannot. Syft and Trivy lead this category. They are essential when you did not build the artifact yourself.
Most production embedded programmes need both. Build-time tools cover everything you control; binary scanners catch third-party modules, vendor firmware blobs and historical artifacts.
Build-time tools
Yocto/OpenEmbedded — create-spdx
Yocto's create-spdx class is the most complete build-time SBOM generator for embedded Linux. Per the Yocto documentation:
"The OpenEmbedded build system generates such information by default (by inheriting the create-spdx class in INHERIT_DISTRO)."
The output is an SPDX JSON document — IMAGE-MACHINE.spdx.json — containing components, licenses, dependencies, sources, the changes applied to each component, and the known vulnerabilities that were fixed. Supplementary classes extend coverage:
cargo_common— Rust cratesgo-mod— Go modulespypi— Python packagesnpm— Node.js packagescpan*— Perl modules
Strengths: complete dependency graph from the same recipes that build the binary; exact licence and version data; native SPDX output that maps to ISO/IEC 5962:2021; well-integrated with Yocto's existing CVE checker.
Limitations: SPDX only — no native CycloneDX output (you must convert downstream); requires the build to actually run through Yocto, not a black-box vendor SDK; updates require a rebuild.
Buildroot — manifest exports
Buildroot does not ship a single-class SBOM generator, but make legal-info produces a manifest of packages, versions, licenses and source URLs. Third-party converters (e.g. buildroot-cyclonedx) turn the manifest into a CycloneDX BOM. For Buildroot-based products, the manifest-plus-converter approach is the closest analogue to Yocto's create-spdx.
Language-specific CycloneDX generators
For code that isn't built through a top-level integration system, the OWASP CycloneDX project maintains per-ecosystem generators:
cyclonedx-python— generates CycloneDX from Python requirements and Poetry/Pipenv/PDM lock filescyclonedx-node-npm— generates CycloneDX from npm/pnpm/yarn lockfilescyclonedx-go— generates CycloneDX from go.mod and go.sumcyclonedx-bom— generic .NET, Java/Maven and Gradle generatorscyclonedx-rust-cargo— generates CycloneDX from Cargo.lock
All emit CycloneDX 1.7 JSON or XML out of the box.
Filesystem and image scanners
Syft (Anchore)
Syft is a CLI and Go library purpose-built for SBOM generation. Its README describes the tool as generating "SBOMs for container images, filesystems, archives" and notes support for signed SBOM attestations via the in-toto specification.
Format support:
- CycloneDX (JSON, XML, Protocol Buffers — matching the ECMA-424 specification)
- SPDX (JSON, tag-value)
- Syft's own JSON format
- Conversion between formats
Ecosystem coverage:
- Linux package managers: Alpine (apk), Debian (dpkg), RPM
- Language ecosystems: Go, Python, Java, JavaScript, Ruby, Rust, PHP, .NET and others
- Targets: container images (OCI, Docker, Singularity), filesystems, archives
Strengths: deep ecosystem coverage; clean SBOM-only focus; high-quality CycloneDX and SPDX output; pairs natively with Grype for downstream vulnerability matching.
Limitations: does not detect statically-linked code in stripped binaries; does not natively understand a vendor firmware blob — you must extract the filesystem first.
Trivy (Aqua Security)
Trivy is a multi-scanner that produces SBOMs alongside other security findings. Its target list is broader than Syft's:
- Container images
- Filesystems
- Git repositories (remote)
- Virtual machine images
- Kubernetes clusters
Scanning capabilities include OS packages and software dependencies (with SBOM generation), known CVEs, infrastructure-as-code misconfigurations, sensitive information and secrets, and software licenses. SBOM output supports both CycloneDX and SPDX.
Strengths: one tool, multiple workflows; built-in CVE matching; broad target coverage including VM images; tight CI integration.
Limitations: SBOM emission is one of many features, not the primary focus; same binary-blob limitation as Syft.
Comparison
| Capability | Syft | Trivy |
|---|---|---|
| SBOM is the primary focus | ✅ | Secondary capability |
| CycloneDX output | ✅ | ✅ |
| SPDX output | ✅ | ✅ |
| Container image scanning | ✅ | ✅ |
| Filesystem scanning | ✅ | ✅ |
| VM image scanning | Limited | ✅ |
| Git repo scanning | ✅ | ✅ |
| Kubernetes scanning | Via integrations | ✅ Native |
| Signed SBOM attestations | ✅ (in-toto) | Limited |
| Native CVE matching | Via Grype | ✅ |
| IaC misconfiguration scanning | ❌ | ✅ |
| Secret detection | ❌ | ✅ |
For pure SBOM emission, Syft is the more focused tool. For a single CI step that produces SBOM plus CVE plus secret plus IaC findings, Trivy reduces tool count.
Firmware-specific tooling
When you have a vendor-shipped firmware blob with no source build available, filesystem scanners need help. The two main tools are Binwalk and EMBA.
Binwalk
Binwalk was rewritten in Rust for speed and accuracy. Per the README:
"Binwalk can identify, and optionally extract, files and data that have been embedded inside of other files."
It identifies a wide variety of file types, includes entropy analysis to flag compressed or encrypted regions, and supports embedded-filesystem extraction. Latest stable release at the time of this article is v3.1.0 from 31 October 2024.
Binwalk does not produce an SBOM by itself. It produces the inputs (extracted filesystems) that Syft or Trivy can then scan.
EMBA
EMBA is a firmware-analysis platform that orchestrates the full pipeline: extraction, static analysis, optional dynamic analysis via emulation, and vulnerability reporting. It detects insecure binaries, outdated software components, vulnerable scripts and hard-coded credentials. It produces SBOMs via dedicated scan profiles — including the default-sbom.emba profile.
EMBA's strength is orchestration. For a firmware blob where you do not know what extraction tool to run, what scanner to apply, or how to chain the steps, EMBA produces a defensible analysis output without manual choreography.
One email at launch · cancel any time
SBOM format choice — SPDX or CycloneDX
CRA Annex I Part II requires the SBOM in "a commonly used and machine-readable format covering at the very least the top-level dependencies of the products". The two formats universally treated as satisfying that wording are:
- SPDX — governed by the Linux Foundation, recognised as ISO/IEC 5962:2021 since August 2021. Current release: SPDX 3.0.0 (April 2024), with SPDX 2.3 (August 2022) still in wide use.
- CycloneDX — governed by the OWASP Foundation and Ecma International (ECMA-424). Current release: CycloneDX 1.7, with the ECMA-424 publication date of 10 December 2025. Formats: JSON (
application/vnd.cyclonedx+json), XML (application/vnd.cyclonedx+xml) and Protocol Buffers.
A detailed format comparison sits in CycloneDX vs SPDX for hardware. The summary: SPDX is the more mature legal/licence-focused format with deep ISO standing; CycloneDX is the more vulnerability- and supply-chain-focused format with native support for HBOM (Hardware BOM), SaaSBOM and cryptographic asset transparency. Neither is "wrong" for the CRA. Pick the one your downstream platform (Anchore, Dependency-Track, Aqua, vendor portal) consumes most easily.
Honest residual gaps
Every SBOM tool we have discussed has a known limitation. A truthful CRA programme acknowledges them.
- Statically-linked code is invisible to package-manager-based scanners. If a vendor compiled OpenSSL directly into their proprietary binary, neither Syft nor Trivy will see it. Workarounds: Yocto's create-spdx (which knows the recipe), source-level CycloneDX generators, or string-matching scanners (less reliable).
- Stripped binaries have lost their symbol table. Heuristic detection by symbol fingerprinting fails. EMBA and Binwalk's extraction help, but pure symbol-free binaries remain opaque.
- In-house libraries with no package-database entry appear as unknown. The SBOM honest-records them but cannot version-match them against any CVE database.
- Firmware blobs from third-party modules (Wi-Fi, BT, cellular SoCs) are typically signed and encrypted. You cannot extract them, so they appear in the SBOM as a single sealed component with whatever metadata the supplier provides — often nothing.
- Yocto's SBOM covers what Yocto knows. Out-of-tree kernel modules, vendor SDK binaries pulled in late in the build, or post-build manual additions can escape create-spdx unless explicitly recipe-d.
A CRA Annex I Part II programme must therefore include a documented residual-risk statement: which components could not be enumerated, why, and what compensating monitoring is in place.
Putting it together — a reference embedded SBOM pipeline
For a Yocto-based connected radio product:
- CI build — Yocto image build with
INHERIT_DISTRO += "create-spdx". Output: SPDX 3.0.0 JSON for the image plus per-package SPDX records. - Format conversion —
spdx2cyclonedx(or syft converting) emits a CycloneDX 1.7 SBOM alongside the SPDX SBOM for distribution. - Cross-check — Syft scans the final image rootfs and reports any components Yocto missed (vendor SDK binaries, out-of-tree modules). Any gap is investigated and resolved at the recipe level, not papered over.
- Vulnerability matching — Grype consumes the Syft SBOM against the OSV / NVD databases. OWASP Dependency-Track consumes the CycloneDX SBOM for portfolio-wide CVE correlation.
- Artifact storage — SPDX + CycloneDX SBOMs stored in the same artifact repository as the firmware binary, with a checksum binding each SBOM to the exact image hash.
- Distribution — Customer-facing SBOM URL on the support page where appropriate (Annex II information requirements and the Article 13 user-information duties shape what the manufacturer must publish; the SBOM itself is typically shared with notified bodies and market surveillance authorities, with a customer-facing summary).
For a vendor-blob-based product where you do not control the build, the pipeline collapses to: Binwalk + EMBA extract → Syft + Trivy scan → residual-risk statement → distribution. The SBOM is honest but partial; the residual-risk statement is what carries the regulatory weight.
Common mistakes
- Generating only one SBOM "for compliance" and forgetting it. The SBOM is a working artifact for vulnerability handling, not a paper deliverable. If you cannot regenerate it from your CI, you cannot satisfy Annex I Part II.
- Treating Syft and Trivy as equivalent. They overlap heavily but Syft is SBOM-first, Trivy is multi-scanner. Pick by use case.
- Skipping the build-time path when Yocto is available. A Yocto build with create-spdx produces a far more complete SBOM than any binary scan. Use binary scanners as a backstop, not as the primary source.
- Forgetting language-ecosystem coverage. A Yocto SBOM may miss Python packages installed at runtime, or Go modules in a sidecar binary. Pair build-time SBOM with per-ecosystem generators where needed.
- Picking a format your downstream stack does not support. Anchore Enterprise consumes SPDX natively; OWASP Dependency-Track is CycloneDX-native. Choose the format that matches your platform, then convert for redistribution.
- Skipping the residual-risk statement. No SBOM is complete for a real-world embedded product. The compliance posture is "here is what we found, here is what we could not enumerate, here is how we monitor the gap". Pretending the SBOM is complete is worse than acknowledging the gap.
How Cenitia helps
Cenitia accepts SPDX and CycloneDX SBOMs from any source — Yocto create-spdx, Buildroot manifest exports, Syft, Trivy, EMBA, CycloneDX language generators, manual uploads — and reconciles them into a single per-product, per-version SBOM record. The platform runs the SBOM against the OSV, NVD and ENISA vulnerability databases continuously, surfacing new CVEs against deployed product versions. For each CRA Annex I Part II requirement — identification of vulnerabilities and components, address-and-remediate, public disclosure — the technical file links directly to the SBOM artifact, the CVE matching record, and the patched-version history.
When a new SBOM format release (CycloneDX 1.8 or SPDX 3.1) lands, Cenitia's tooling watcher flags every product whose SBOM should be re-emitted in the newer format.
One email at launch · cancel any time
Frequently asked questions
Which SBOM format does the CRA require — SPDX or CycloneDX?
Neither, by name. CRA Annex I Part II requires an SBOM in "a commonly used and machine-readable format covering at the very least the top-level dependencies of the products". The two formats universally accepted as satisfying that wording are SPDX (ISO/IEC 5962:2021) and CycloneDX (ECMA-424). Both are open standards, both have a strong ecosystem of tooling, and both are accepted by the major vulnerability and licence platforms. The choice between them is a tooling-fit decision, not a regulatory one.
What is the difference between Syft and Trivy for embedded SBOM work?
Syft (Anchore) is purpose-built for SBOM generation. It supports CycloneDX, SPDX and Syft JSON output, scans dozens of package ecosystems including Linux package managers (apk, dpkg, RPM) and most language ecosystems, and supports signed SBOM attestations via the in-toto specification. Trivy (Aqua Security) is a multi-scanner: it produces SBOMs but also scans the same target for CVEs, infrastructure-as-code misconfigurations, secrets and licence issues. For pure SBOM emission on an embedded rootfs, Syft is the cleaner tool; for combined vulnerability + SBOM workflows, Trivy reduces the number of tools to run.
Can I generate an SBOM directly from a Yocto build?
Yes. Yocto/OpenEmbedded has a built-in "create-spdx" bbclass. The OpenEmbedded build system generates an SPDX SBOM by default by inheriting create-spdx in INHERIT_DISTRO. The output is a JSON file named IMAGE-MACHINE.spdx.json. Supplementary classes (cargo_common, go-mod, pypi, npm, cpan*) extend coverage for language-specific ecosystems. The build-time SBOM is the gold standard because it is generated from the same recipes that build the binary, so the dependency graph is complete and accurate without inference.
Why do binary-scan SBOM tools miss things?
Three reasons. First, statically-linked code does not advertise itself the way a package manager record does — the compiler has merged it into a flat ELF. Second, stripped binaries have lost their symbol table, so heuristic detection by symbol fingerprinting fails. Third, custom or in-house libraries that are not in any package database show up as unknown. EMBA, Syft and Trivy all have honest limitations on binary-only scanning — the right answer is to generate the SBOM at build time where possible and use binary scanners as a backstop for third-party components you did not build.
Do I need separate tools for containers and bare-metal embedded firmware?
Often yes. Container images have a well-defined layer + package-database structure that Syft and Trivy parse natively. Bare-metal embedded firmware blobs typically need extraction first — Binwalk to identify and extract the embedded filesystem, then Syft or Trivy on the extracted rootfs, with EMBA orchestrating the whole pipeline. If your embedded device boots a Yocto- or Buildroot-built image, the cleanest path is build-time SBOM from those tools and a binary scan only as cross-check.
How often do I need to regenerate the SBOM?
Every change to the shipped binary that adds, removes or upgrades a component requires a fresh SBOM. CRA Annex I Part II ties SBOM upkeep to the vulnerability handling process — see our companion article on SBOM update frequency under the CRA. The practical rule: regenerate the SBOM in the same CI pipeline that produces the firmware artifact, and store the SBOM alongside the artifact with a checksum binding.
Related from the Library
- SBOM update frequency requirements under CRA
- CycloneDX vs SPDX for hardware
- CRA Annex I explained
- Technical File for IoT devices
- CRA December 2027 readiness
Further reading
- Regulation (EU) 2024/2847 — Cyber Resilience Act, EUR-Lex
- Yocto Project — SPDX SBOM documentation
- Syft (Anchore) on GitHub
- Trivy (Aqua Security) on GitHub
- CycloneDX specification overview
- SPDX project — About
- Binwalk on GitHub
- EMBA on GitHub
- OWASP Dependency-Track
- Anchore Grype
Last reviewed: 5 July 2026. Cited tools and standards watched continuously by Cenitia — when a new format release or major tool change lands, this article is flagged for update.
FAQ
Frequently asked questions
Which SBOM format does the CRA require — SPDX or CycloneDX?
Neither, by name. CRA Annex I Part II requires an SBOM in 'a commonly used and machine-readable format covering at the very least the top-level dependencies of the products'. The two formats universally accepted as satisfying that wording are SPDX (ISO/IEC 5962:2021) and CycloneDX (ECMA-424). Both are open standards, both have a strong ecosystem of tooling, and both are accepted by the major vulnerability and licence platforms. The choice between them is a tooling-fit decision, not a regulatory one.
What is the difference between Syft and Trivy for embedded SBOM work?
Syft (Anchore) is purpose-built for SBOM generation. It supports CycloneDX, SPDX and Syft JSON output, scans dozens of package ecosystems including Linux package managers (apk, dpkg, RPM) and most language ecosystems, and supports signed SBOM attestations via the in-toto specification. Trivy (Aqua Security) is a multi-scanner: it produces SBOMs but also scans the same target for CVEs, infrastructure-as-code misconfigurations, secrets and licence issues. For pure SBOM emission on an embedded rootfs, Syft is the cleaner tool; for combined vulnerability + SBOM workflows, Trivy reduces the number of tools to run.
Can I generate an SBOM directly from a Yocto build?
Yes. Yocto/OpenEmbedded has a built-in 'create-spdx' bbclass. The OpenEmbedded build system generates an SPDX SBOM by default by inheriting create-spdx in INHERIT_DISTRO. The output is a JSON file named IMAGE-MACHINE.spdx.json. Supplementary classes (cargo_common, go-mod, pypi, npm, cpan*) extend coverage for language-specific ecosystems. The build-time SBOM is the gold standard because it is generated from the same recipes that build the binary, so the dependency graph is complete and accurate without inference.
Why do binary-scan SBOM tools miss things?
Three reasons. First, statically-linked code does not advertise itself the way a package manager record does — the compiler has merged it into a flat ELF. Second, stripped binaries have lost their symbol table, so heuristic detection by symbol fingerprinting fails. Third, custom or in-house libraries that are not in any package database show up as unknown. EMBA, Syft and Trivy all have honest limitations on binary-only scanning — the right answer is to generate the SBOM at build time where possible and use binary scanners as a backstop for third-party components you did not build.
Do I need separate tools for containers and bare-metal embedded firmware?
Often yes. Container images have a well-defined layer + package-database structure that Syft and Trivy parse natively. Bare-metal embedded firmware blobs typically need extraction first — Binwalk to identify and extract the embedded filesystem, then Syft or Trivy on the extracted rootfs, with EMBA orchestrating the whole pipeline. If your embedded device boots a Yocto- or Buildroot-built image, the cleanest path is build-time SBOM from those tools and a binary scan only as cross-check.
How often do I need to regenerate the SBOM?
Every change to the shipped binary that adds, removes or upgrades a component requires a fresh SBOM. CRA Annex I Part II ties SBOM upkeep to the vulnerability handling process — see our companion article on SBOM update frequency under the CRA. The practical rule: regenerate the SBOM in the same CI pipeline that produces the firmware artifact, and store the SBOM alongside the artifact with a checksum binding.
Continue reading
Related guides
reference
SBOM for legacy embedded firmware: building one from binaries when source is gone
Build an SBOM for legacy embedded firmware from binaries — Binwalk extraction, Syft + Trivy scan, EMBA triage, and an honest residual-risk template for CRA Annex I Part II.
12 min read
guide
SBOM update frequency under CRA: release-based maintenance and historic retention
How often the SBOM must be updated under CRA Annex I Part II item (1) and Annex VII — release-based maintenance, historic version retention, and vulnerability monitoring cadence.
8 min read
guide
SBOM for hardware manufacturers — CycloneDX vs SPDX practical guide
Practical SBOM guide for hardware manufacturers in 2026: CycloneDX vs SPDX format comparison, generation tooling, maintenance lifecycle, and CRA Annex I compliance.
12 min read
reference
EN 55032 — EMC emissions classes A and B for ITE
Reference on EN 55032 (CISPR 32) emissions classes A and B for multimedia equipment — limits, frequency ranges, and presumption of conformity under the EMC Directive.
8 min read
Put this into practice
Free tools & references
- CRA Readiness CheckerScore your product against the Cyber Resilience Act essential requirements.Open tool →
- EU Directive SelectorDescribe your product and find which EU directives and regulations apply.Open tool →
New to the terminology? Browse the compliance glossary — plain-English, citation-backed definitions of every term above.