How to Generate an SBOM for a Container Image

How to generate and verify a container SBOM
Key takeaways
- Generate at build time, against the built image. Source-stage SBOMs miss resolved versions and the entire OS package layer.
- Emit SPDX and CycloneDX together. Different consumers in your stack expect different formats, and emitting both removes a whole class of integration failures.
- Bind to digests, not tags, and sign with cosign. An unsigned SBOM that floats free of a digest is not evidence.
- Pair the SBOM with VEX and provenance. The inventory, the exploitability context, and the build history answer three different auditor questions.
- A smaller base image is the highest-leverage change. Fewer components means a shorter SBOM, fewer findings, and less remediation work downstream.
To produce a container SBOM that holds up under audit, generate it from the built image rather than from source manifests, emit it in SPDX or CycloneDX, sign it with cosign, and attach it to the image digest it describes. An SBOM that is not tied to a specific digest and not signed is an inventory, not evidence. The three steps below take roughly as long as adding a scan step to your pipeline.
What has to be inside a container SBOM
An SBOM is a structured inventory of every component, library, and dependency inside a piece of software. The NTIA's minimum-elements guidance sets the floor, and most assessors treat it as the baseline:
- Supplier name - who created the component
- Component name and version
- Unique identifiers - PURLs (Package URLs) or CPEs
- Dependency relationships - whether a component is direct or transitive
- Author of the SBOM data and a timestamp
For containers, there is a practical addition: the SBOM has to cover the operating-system package layer, not just your application's language dependencies. A Node or Python manifest tells an assessor nothing about the OpenSSL build sitting underneath it.
Generate at build time, not from source
An SBOM can be produced at three points in the lifecycle, and they do not catch the same things.
Build-stage generation is the most accurate way to capture what a container actually contains, because it records the state of the software as it is being assembled. Source-stage output is useful for shifting left, but it is not the artifact you hand an auditor.
Practical rule: run generation as a pipeline step immediately after the image build, against the image you just produced, and fail the build if the step fails.
Which format should you emit - SPDX or CycloneDX?
Both. The two formats are the agreed industry standards, and they are consumed by different parts of a typical stack: SPDX tends to dominate license and federal-compliance workflows, CycloneDX tends to dominate vulnerability and VEX workflows. Emitting both costs one extra flag and removes an entire class of "our scanner can't read this" conversations later.
Alongside the format, two companion artifacts matter:
- VEX (Vulnerability Exploitability eXchange) lets you mark findings as non-exploitable so your SBOM consumers can filter noise rather than triage it.
- Provenance attestations record how and where the artifact was built, which is the part of the chain an SBOM alone does not cover.
If you are choosing a generator, we compared the options in 10 best SBOM generation tools - including where each one sits in a pipeline and which ones only consume SBOMs rather than produce them. OWASP Dependency-Track, for example, is an analysis platform: it needs a generator such as Syft or Trivy to produce the SBOM before it can do anything with it. Teams comparing sbom tools often miss that distinction and end up with a dashboard and no source of data.
Sign the SBOM and bind it to the image digest
This is the step most pipelines skip, and it is the step that turns an inventory into evidence.
- Sign the image and the SBOM with cosign/sigstore, keylessly if your CI supports OIDC.
- Attach the SBOM as an OCI artifact against the image digest, not the tag. Tags move; digests do not.
- Push the signature, the SBOM, and the provenance attestation to the same registry as the image, so they travel together.
An SBOM stored in a build-log bucket, keyed by build number, is unverifiable six months later. An SBOM attached to a sha256 digest is checkable by anyone with pull access.
Verify before you trust
Verification is three assertions, and all three should run in your admission or release gate. Most sbom tools will happily emit a document regardless, so the gate has to do this work rather than the generator:
- The signature is valid and chains to an identity you expect (a specific CI workflow, not "anyone in the org").
- The SBOM's subject digest matches the image you are about to deploy.
- The component list is plausible - an SBOM for a minimal image that lists several hundred OS packages usually means it was generated against the wrong layer or the wrong stage.
Why the base image decides how painful all of this is
Every component in your base image becomes a row in your SBOM, a line in your POA&M, and a potential ticket when a CVE lands. The cheapest way to make SBOM work tractable is to start from an image that has fewer things in it.
Concrete, sourced points:
- Echo ships every tag with a corresponding SBOM, in both SPDX and CycloneDX, so there is no generation step to own for the base layer (Echo container images).
- Images are built on SLSA Build Level 3 infrastructure and delivered signed and attested, with SBOM, provenance, and VEX (Echo container images).
- Artifacts are signed and attestable via cosign and sigstore (Echo DORA page).
- Echo's published SLA commits to patching critical and high CVEs within 7 business days and medium and low within 10 (Echo Images and Libraries SLA, last updated 10 May 2026).
- Images are recognised by the major third-party scanners, including Trivy, Grype, Wiz, Orca, Snyk, and JFrog Xray, so SBOM output is consumable without proprietary tooling (Echo container images).
If you want the end-to-end version of this, including how clean base layers change what your scanners report, see building a zero-CVE container image pipeline.
Three mistakes that make SBOMs useless
- Generating once, at release. A new vulnerability disclosed next week needs an SBOM that reflects what you shipped, not what you planned to ship. Regenerate on every build.
- Keying to tags. A "latest" tag means something different tomorrow. Bind to digests.
- Treating the SBOM as the deliverable. The deliverable is the ability to answer "where are we running this component?" in seconds. That requires the SBOMs to be centrally searchable, not scattered across build artifacts.
FAQ
Do I need an SBOM if I already scan my images?
Yes, and they answer different questions. A scanner tells you which known vulnerabilities are present today. An SBOM tells you which components are present, which is what you need when a vulnerability is disclosed tomorrow and you have to find every affected service immediately. Regulations including US Executive Order 14028 ask for the inventory, not just the scan result.
Should I generate the SBOM from the Dockerfile or the built image?
From the built image. A Dockerfile declares intent; the image is what actually shipped. Build-stage generation captures resolved versions, transitive dependencies, and the operating-system package layer that manifest parsing never sees. Generating from source is useful for early license checks, but it is not the artifact to put in front of an assessor or a customer.
What is the difference between SPDX and CycloneDX?
Both are standard, machine-readable SBOM formats, and most mature toolchains emit either. In practice SPDX appears more often in licence and federal-compliance workflows, while CycloneDX is more common in vulnerability and VEX pipelines. Because consumers differ, emitting both is the low-friction choice. Echo images ship in both formats for exactly this reason.
How do I prove an SBOM has not been tampered with?
Sign it. Using cosign and sigstore, you sign the SBOM and attach it to the image digest as an OCI artifact, then verify the signature and the subject digest in your admission gate. That gives you a cryptographic link between a specific image and a specific component list - the assurance auditors and downstream customers actually ask for.
Frontier models can now find and exploit zero days in your code
Find out what to do when there's no CVE, scanner alert or fix available yet.
What are the 7 blind spots in your vulnerability scans?
Discover when "0 vulnerabilities" doesn't actually mean you're clean.





.avif)
.avif)