Generating an SBOM for what you ship

A software bill of materials is the list of every component inside something you ship, with its version, in a format other tools can read. The Regulation requires one for every product, covering at least the top-level dependencies, and the reporting duty is unworkable without one: you cannot say whether a vulnerability in a component affects your product if you cannot say which products contain it.Annex I Part II⁠(1)⁠

The one-minute version, with syft

Syft is a free, open-source tool from Anchore that builds an SBOM by reading a container image, a source directory or a binary. Install it once and point it at a release.

# Install, on macOS
brew install syft

# ...or anywhere else
curl -sSfL https://get.anchore.io/syft | sh -s -- -b /usr/local/bin

# A container image you ship
syft acme/agent:4.2.1 -o cyclonedx-json > sbom.json

# A source checkout, at the tag you released
syft dir:. -o cyclonedx-json > sbom.json

# A binary or an installer
syft file:./dist/agent-4.2.1.tar.gz -o cyclonedx-json > sbom.json

Replace the image or path with your own. The redirect writes the bill of materials to the file; syft keeps its progress on stderr, so the file stays valid JSON.

Which format

Either of the two standards. CycloneDX 1.4 to 1.7 in JSON or XML, or SPDX 2.2 and 2.3 in JSON. CycloneDX is the more common choice for application software and carries package URLs on every component, which is what a vulnerability advisory is matched against; SPDX is what a licensing team may already produce. If you have neither preference, use CycloneDX JSON.

Per release, from the build

One SBOM per version you still support, generated by the build rather than by hand. A file produced once and kept describes a build that is no longer the one in the field, and an advisory about a component you removed two releases ago will still match it. In a pipeline, the same command runs after the artefact is built and the file is stored beside it.

# GitHub Actions, after the image is built
- run: curl -sSfL https://get.anchore.io/syft | sh -s -- -b /usr/local/bin
- run: syft ghcr.io/acme/agent:${{ github.ref_name }} -o cyclonedx-json > sbom.json
- uses: actions/upload-artifact@v4
  with: { name: sbom, path: sbom.json }

Many build tools also emit CycloneDX directly through a plugin, for Maven, Gradle, npm, .NET and others. Whichever produces the list closest to what actually ships is the right one.

What to do with it

Check it, first. The free SBOM check matches the file against the catalogue of vulnerabilities being exploited in the wild and shows what comes back, without an account and without storing the file. A hit there is a reason to assess whether your product is affected; it is not by itself a reportable event.

The map of your components is sensitive. The security page says exactly what happens to an uploaded SBOM, in the check and in the product.

This produces evidence, timelines and drafts. It is not legal advice, and you remain the party responsible for reporting.