how to generate an SBOM with syft
A step-by-step skill for generating a software bill of materials with Syft: installing, scanning images and directories, choosing CycloneDX or SPDX output, and wiring generation into CI. Use when an engineer or agent needs an SBOM for compliance, asks what is inside a container image, or feeds package lists to a vulnerability scanner. Triggers: generate SBOM with syft, syft cyclonedx, SBOM for container image. Not for: runtime vuln monitoring, deep license review, unsupported artifact types.
how to generate an SBOM with syft
TL;DR
Install Syft, point it at your container image or source directory (syft [image] -o cyclonedx-json), and it inventories every package it can find into a standard SBOM format. Attach the SBOM to your releases and feed it to your vulnerability scanner so you know exactly what shipped. Regenerate it on every build; an SBOM from last quarter describes software you no longer run.
The query
how to generate an SBOM with syftUse this when
- you need a software bill of materials for compliance or a customer questionnaire
- someone asks "what is actually inside this container image"
- you want to feed accurate package lists to a vulnerability scanner
- you are setting up SBOM generation in CI
Not for this skill when
- you need runtime vulnerability monitoring (an SBOM is a point-in-time inventory)
- you are auditing license compliance deeply (SBOM helps, but you still need license review)
- your artifact is not a container, filesystem, or language ecosystem Syft understands
Steps
- Install Syft from the official install script or your package manager, then run
syft version.
Expected output: a version string confirming the binary works.
- Generate from a container image: run
syft [your image tag] -o cyclonedx-jsonand save the output to sbom.json.
Expected output: sbom.json contains a CycloneDX document listing packages, versions, and licenses.
- Generate from a source directory: run
syft mount the host path dir at container path /path/to/repo -o spdx-jsonand save the output to sbom-spdx.json.
Expected output: language packages from manifest files (package.json, requirements files, go.mod) are inventoried.
- Sanity-check the output: search the SBOM for a dependency you know is in the app and confirm its version matches.
Expected output: the known package appears with the correct version.
- Attach it to the release: upload sbom.json as a release asset next to the image, and store one per build in your artifact store.
Expected output: every release has a matching SBOM retrievable by tag.
- Wire it into CI: generate the SBOM on every image build and fail or warn when a scan of it finds critical CVEs.
Expected output: builds produce a fresh SBOM and known-bad components block the pipeline.
Variant: SPDX instead of CycloneDX
Use -o spdx-json or -o spdx-tag-value. Pick the format your customers or auditors ask for; Syft produces both from the same scan.
Variant: scanning a running container
Point Syft at the image the container was started from rather than the live container. Live-container diffs are for forensics, not for SBOMs.
Variant: attestations
Pair the SBOM with a signed attestation so consumers can verify the SBOM actually describes the image they pulled.
Why this happens
Nobody can patch what they cant see. Modern images stack a base OS, language runtimes, and hundreds of transitive dependencies, and "we think we updated that library" is not an answer auditors or customers accept. An SBOM turns the contents into a queryable list.
Edge cases and pitfalls
- Syft catalogs what it can see: statically linked binaries and vendored code without manifests may be missed. Note the gaps.
- Multi-arch images need one SBOM per architecture or a merged one; document which you publish.
- SBOMs go stale the moment you rebuild. Generate per build, never reuse across releases.
- Large monorepos produce huge SBOMs. Scope Syft to the shipped artifact, not the whole repo.
Provenance
Resolved from the public thread: https://vectle.com/posts/pst__jZWDwuP9h52HqGi3TsR9g
Maintainer review
No maintainer verification is recorded for this version.
This records the version a maintainer checked. It does not assert that the version is the latest upstream release.