⚠️ Before proceeding to read the documentation, please verify that you are on the correct branch for your Yocto release, as the feature set and default configurations may vary!
meta-cyclonedx is a Yocto meta-layer which
produces CycloneDX Software Bill of Materials
(aka SBOMs) from your target root filesystem.
This layer generates CycloneDX compliant SBOMs with the following features:
- Currently, support for CycloneDX specification 1.7, 1.6, and 1.4
- Support for multiple supported Yocto (LTS) releases.
- Improved package matching against the NIST NVD by fixing CPE generation process.
- Included purl package URLs.
- Added generation of an additional CycloneDX VEX file which contains information on patched and ignored CVEs from within the OpenEmbedded build system.
- Component scopes to differentiate between runtime (
required) and build-time (optional) dependencies, enabling per-use-case SBOM filtering. - Include component licenses.
- Added option to reduce the SBOM size by limiting SBOM collection to run-time packages (which might potentially come at some expense)
This repository was originally forked from the BG Networks repository.
To install this meta-layer simply clone the repository into the sources
directory, check out the corresponding branch for your Yocto release
(e.g. scarthgap, kirkstone, ...)
and add it to your build/conf/bblayers.conf file:
cd sources
git clone https://github.com/iris-GmbH/meta-cyclonedx.git
cd meta-cyclonedx
git checkout <YOCTO_RELEASE>and in your bblayers.conf file:
BBLAYERS += "${BSPDIR}/sources/meta-cyclonedx"To enable and configure the layer simply inherit the cyclonedx-export class
in your local.conf file:
INHERIT += "cyclonedx-export"By default, meta-cyclonedx generates CycloneDX 1.6 format SBOMs. You can configure a different version if needed:
CYCLONEDX_SPEC_VERSION = "1.6" # Default - modern format
# Or for newer features:
# CYCLONEDX_SPEC_VERSION = "1.7"
# Or for legacy tools:
# CYCLONEDX_SPEC_VERSION = "1.4"Version differences:
- 1.4: Legacy format for compatibility with older tools
- 1.6: Modern format with enhanced metadata and timestamps (default)
- 1.7: Latest version with advanced cryptography transparency (CBOM), intellectual property visibility, citations, and improved custom license handling
By default, meta-cyclonedx will only include run-time packages in the SBOM, which drastically reduces the number of potentially irrelevant packages. However, this can lead to valid packages being omitted from the SBOM (see here).
If preferred, you can add the following configuration setting (e.g in your local.conf), which will cause meta-cyclonedx to include all build-time packages as well:
CYCLONEDX_RUNTIME_PACKAGES_ONLY = "0"When including both runtime and build-time packages, meta-cyclonedx uses CycloneDX component scopes to differentiate between them:
- Runtime packages are marked with
"scope": "required" - Build-time only packages are marked with
"scope": "optional"
This allows tools to filter components based on their use case:
- CVE matching: Focus on components with
"scope": "required" - License compliance: Include all components regardless of scope
- Supply chain tracking: Include all components regardless of scope
Component scopes are enabled by default and available in both CycloneDX 1.4 and 1.6 specifications. If you need to disable them (e.g., for compatibility with certain SBOM profiles or tools):
CYCLONEDX_ADD_COMPONENT_SCOPES = "0"By default, vulnerability analysis records include firstIssued and lastUpdated
timestamps when using CycloneDX 1.6. To generate minimal VEX documents without timestamps:
CYCLONEDX_ADD_VULN_TIMESTAMPS = "0"By default, component licenses are included in the SBOM.
You may choose to exclude license information from your SBOM:
CYCLONEDX_ADD_COMPONENT_LICENSES = "0"The licenses data is taken from the component recipe (see LICENSE. Single licenses are matched against a list of known SPDX licenses where possible.
If multiple licenses are specified using & or |, the license is converted
into a SPDX license expression.
Additionally, simple expressions (only containing "AND" operators) are split into multiple license entries by default, improving the SBOM data quality. Note however, that this might not be supported by your SBOM consuming tool of choice (e.g. DependencyTrack).
To disable this feature you can set
CYCLONEDX_SPLIT_LICENSE_EXPRESSIONS = "0"When using CycloneDX 1.7, you can enable additional optional features for enhanced SBOM quality:
For custom or proprietary licenses (appearing as LicenseRef-* in expressions), you can include the actual license text in the SBOM:
CYCLONEDX_ADD_LICENSE_DETAILS = "1" # default: enabled for 1.7This feature extracts license text from:
- Yocto's
COMMON_LICENSE_DIR(e.g.,/meta/files/common-licenses/) - Package-specific license files referenced in
LIC_FILES_CHKSUM
The license text is embedded in the SBOM's expressionDetails field, enabling SBOM consumers to view the full license content without external lookups.
Citations document the SBOM's provenance and generation methodology:
CYCLONEDX_ADD_CITATION = "1" # default: enabled for 1.7This adds metadata tracking the source of the SBOM (meta-cyclonedx layer) and enables supply chain transparency.
For enterprise environments, you can mark SBOMs with TLP distribution restrictions:
CYCLONEDX_TLP_MARKING = "GREEN" # options: CLEAR, GREEN, AMBER, AMBER_STRICT, REDTLP markings control how the SBOM can be shared:
CLEAR: Unlimited distributionGREEN: Community-wide distributionAMBER: Limited distribution to organizationsAMBER_STRICT: Limited distribution to specified recipients onlyRED: Personal for named recipients only
Leave empty (default) to omit TLP marking.
The following CycloneDX 1.7 features are not currently supported due to the high implementation complexity and lack of native Yocto support:
Cryptography Bill of Materials (CBOM)
- Documents cryptographic algorithms, certificates, keys, and protocols
- Use case: Post-quantum cryptography (PQC) readiness and compliance
- Why unsupported: Requires binary analysis tools to detect crypto usage in compiled packages. Yocto does not natively track cryptographic algorithms used by components.
- Manual workaround: Use the
propertiesfield to add custom crypto metadata if needed
Patent Assertions
- Documents patent ownership, licensing, and defensive termination clauses
- Use case: IP due diligence, M&A activities, patent litigation defense
- Why unsupported: Requires manual legal research and patent database maintenance per package. Open source recipes do not include patent information.
- Manual workaround: Use the
propertiesfield or external SBOM enrichment tools
If you have specific requirements for these features, consider using external SBOM enrichment tools after generation or contributing implementations that integrate with specialized crypto scanners.
Meta-cyclonedx supports generating a minimal SBOM that includes only the essential information required by the CycloneDX specification. This is useful for:
- Reducing SBOM file size
- Compliance with minimal SBOM requirements
- Fast SBOM generation
- Environments with strict data minimization policies
The minimal SBOM always contains:
Component Information:
name- Component nameversion- Component versiontype- Component type (typically "library")bom-ref- Unique reference identifier
Identifiers:
cpe- Common Platform Enumeration for vulnerability matchingpurl- Package URL for package identification
Relationships:
dependencies- Component dependency graph
Metadata:
bomFormat,specVersion,serialNumber,versiontimestamp- SBOM generation timetools- SBOM generation tool information
VEX (Vulnerability Exploitability Exchange):
vulnerabilities- CVE status information (patched/ignored)
To generate a minimal SBOM, disable all optional features:
INHERIT += "cyclonedx-export"
# Use minimal configuration
CYCLONEDX_SPEC_VERSION = "1.6" # or "1.4"
CYCLONEDX_RUNTIME_PACKAGES_ONLY = "1" # Runtime packages only
CYCLONEDX_ADD_COMPONENT_SCOPES = "0" # Disable scope marking
CYCLONEDX_ADD_VULN_TIMESTAMPS = "0" # Disable VEX timestamps
CYCLONEDX_ADD_COMPONENT_LICENSES = "0" # Exclude licensesThis produces the smallest valid CycloneDX SBOM with only essential vulnerability and package information.
# Specification version (default: "1.6")
CYCLONEDX_SPEC_VERSION = "1.6" # or "1.7" or "1.4"
# Include build-time packages (default: "1" = runtime only)
CYCLONEDX_RUNTIME_PACKAGES_ONLY = "1"
# Add component scopes (default: "1")
CYCLONEDX_ADD_COMPONENT_SCOPES = "1"
# Add vulnerability timestamps in 1.6+ (default: "1")
CYCLONEDX_ADD_VULN_TIMESTAMPS = "1"
# Add component licenses (default: "1")
CYCLONEDX_ADD_COMPONENT_LICENSES = "1"
# split license expressions into multiple license entries
# when possible (default: "1")
CYCLONEDX_SPLIT_LICENSE_EXPRESSIONS = "1"
# CycloneDX 1.7 optional features
CYCLONEDX_ADD_LICENSE_DETAILS = "1" # Include license text for custom licenses
CYCLONEDX_ADD_CITATION = "1" # Document SBOM provenance
CYCLONEDX_TLP_MARKING = "" # TLP marking (CLEAR|GREEN|AMBER|AMBER_STRICT|RED)
# Include unpatched vulnerabilities in VEX (default: "0").
# If enabled, the cve-check class is inherited to query the NVD.
# Note that querying the NVD happens at the time of running the
# task, which currently requires rootfs generation. You may
# want to use external tools such as DependencyTrack for regular analysis.
CYCLONEDX_INCLUDE_UNPATCHED_VULNS = "1"
# State to assign to unpatched vulnerabilities (default: "in_triage").
# Can be empty to omit the state field.
CYCLONEDX_UNPATCHED_VULNS_STATE = "in_triage"The default use of cyclonedx-export.bbclass only produces SBOM for recipes
that inherits image.bbclass. In order to produce an SBOM for an image like
recipe that does not generate a filesystem image, and thus not inherits
image.bbclass, you can use the CYCLONEDX_EXPORT_DEPENDS variable to list the
dependencies to consider/include. Something like this
CYCLONEDX_EXPORT_DEPENDS = "${DEPENDS}"The dependencies will be filtered so that non-target recipes are excluded, and
the remaining dependencies will be processed with PREFERRED_PROVIDER_*
variables, so that you can include things like virtual/bootloader and
virtual/kernel.
Note: There is no recursion of CYCLONEDX_EXPORT_DEPENDS, so only the listed
dependencies are included in the SBOM. So while this does allow using with any
kind of recipe, it is in-practise mainly usable for simple compound images, like
a bootloader image consisting of the output from a handful of recipes.
In addition to settting CYCLONEDX_EXPORT_DEPENDS you will also need to hook up
do_populate_cyclonedx and do_deploy_cyclonedx tasks. The
do_populate_cyclonedx task should be added to recrdeptask flag on the recipe
task that produces the image output, and the do_deploy_cyclonedx task should
be added to the recipe.
This is an example of how to produce SBOM for an image recipe using
genimage.bbclass from meta-ptx:
CYCLONEDX_EXPORT_DEPENDS = "${DEPENDS}"
do_genimage[recrdeptask] += "do_populate_cyclonedx"
addtask do_deploy_cyclonedx after do_deploy before do_buildOnce everything is configured simply build your image as you normally would.
By default the final CycloneDX SBOMs are saved to the folder
${DEPLOY_DIR}/${PN}/cyclonedx-export as bom.json and vex.json
respectively.
While this layer does not offer a direct integration with DependencyTrack (we consider that a feature, since it removes dependencies to external infrastructure in your build), it is perfectly possible to use the produced SBOMs within DependencyTrack.
At the time of writing DependencyTrack does not support uploading component
and vulnerability information in one go (which is why we currently create a
separate vex.json file). The status on supporting this may be tracked
here.
- Go into an existing project in your DependencyTrack instance or create a new one.
- Go to the Components tab and click Upload BOM.
- Select the
bom.jsonfile from your deploy directory. - Wait for the vulnerability analysis to complete.
- Go to the Audit Vulnerabilities tab and click Apply VEX.
- Select the
vex.jsonfile from your deploy directory.
You may want to script the upload of the SBOM files to DependencyTrack, e.g. as part of a CI job that runs after your build is complete.
This is possible by leveraging DependencyTracks REST API.
At the time of writing this can be done by leveraging the following API endpoints:
/v1/bomfor uploading thebom.json./v1/event/token/{uuid}for checking the status on thebom.jsonprocessing./v1/vexfor uploading thevex.json.
Please refer to DependencyTracks REST API documentation regarding the usage of these endpoints as well as the required token permissions.
In the future we might include an example script in this repository.
We use the image_list_installed_packages function from upstream
OpenEmbedded as a means to reduce the SBOM contents to packages that are added
to the final resulting rootfs. This drastically reduces the "noise" generated
by CVEs in build-time dependencies. This however comes with some potential
downsides (i.e. Missing some packages), as discussed
here.
OpenEmbedded and its core mechanisms work best with "traditional" programming languages such as C and C++, as these are the languages that they were initially designed around. For instance, a core-assumption prevalent in many OE mechanisms (including those we depend on in meta-cyclonedx) is that each library is described in its own OE recipe. This however does not work well with many modern programming languages, which often come with their own package managers (e.g. NPM, Cargo, Go Modules, ...), which do not necessarily integrate well into the OpenEmbedded ecosystem and depend of potentially hundreds of external dependencies (good luck writing a separate OE recipe for each dependency in a small-medium sized Node.js project).
Thus, if you rely on packages written in programming languages that come with their own package managers, you might be better off with a divide and conquer approach for covering their packages as well (your mileage may vary):
- Use this meta-layer to generate a CycloneDX SBOM which covers your OE-based operating system, system libraries, etc.
- Use tools designed explicitly for generating CycloneDX SBOMs for these languages (e.g. Rust, NPM, Golang, ...)
- Optionally, use some glue code to merge the SBOMs together (cyclonedx-cli offers merge functionality)