Production engineering guide for sbom implementation covering patterns, implementation strategies, and operational best practices.
Software Bill of Materials (SBOM) implementation is the process of systematically capturing, managing, and leveraging a complete inventory of components that make up a software artifact—from source code to container images to deployed services. It matters when software supply chain integrity is critical: during vulnerability management, compliance audits, incident response, and release validation. An SBOM is not a report; it is a living artifact that enables traceability from build to production, and its implementation must be embedded in the CI/CD pipeline, deployment workflows, and security operations.
To generate an SBOM, start with a compiled artifact—such as a Docker image, a JAR, or a ZIP package—and extract its constituent components. The most common approach uses a tool that scans the artifact’s file system, dependencies, and metadata to produce a structured output.
The syft tool from Chainguard is the de facto standard for SBOM generation. It supports a wide range of artifact formats and produces SBOMs in multiple standard formats, including SPDX, CycloneDX, and JSON.
syft -o cyclone-dx-json \
--file-format cyclone-dx-json \
--output ./sbom-cyclone-dx.json \
docker-image:myapp:v1.2.3
This command produces a CycloneDX JSON SBOM that includes:
nginx, python3, openjdk-11)spring-boot-starter-web pulls in spring-core, jackson-databind, etc.)libcrypto.so.1.1, META-INF/MANIFEST.MF)The --file-format flag is crucial: omitting it results in a default spdx-json format, which requires a second conversion step. The --output flag supports stdout, file, and s3://bucket/path targets.
A common failure is assuming the SBOM captures only direct dependencies. In reality, syft dives into archive files (.jar, .zip, .tar.gz, .deb, .rpm) and extracts embedded content, including nested JARs and bundled libraries.
--include-all-files: Enables full file-level inventory. Without it, only top-level files are listed, and nested files (e.g., WEB-INF/lib/) are missed.--exclude: Allows filtering by path, e.g., --exclude '*/test/*' to exclude test artifacts from the SBOM.--skip-dirs: When scanning a directory, --skip-dirs 'node_modules' can reduce noise from large, volatile directories.--trust-registry: When scanning a Docker image, this option pulls metadata (e.g., digest, created, author) from the image registry and includes it in the SBOM.A silent failure occurs when syft defaults to os as the package type, but the artifact contains npm, pypi, or maven packages. These are detected only when --package-type is explicitly set or when the tool inspects package.json, pom.xml, or requirements.txt.
An SBOM is only useful when it is correct and consistent. Validation ensures that the SBOM reflects the actual software artifact.
Use cyclonedx-cli to validate the SBOM’s schema and content.
cyclonedx validate ./sbom-cyclone-dx.json
This command checks:
bomFormat, specVersion, components, version)1.2.3, v1.0.0, 1.2.3-beta)externalReferences (e.g., url, hash, licenseUrl)component version and version in externalReferencesValidation fails silently if any field is missing or malformed. The error output includes:
{
"error": "Invalid value for 'bomFormat'",
"path": "bomFormat",
"expected": "CycloneDX",
"actual": "cyclonedx"
}
A common mistake is using version in the top-level metadata but forgetting that components must also have their own version. The SBOM can be valid but semantically incorrect—e.g., a spring-boot component lists version: 2.7.0 but the metadata says version: 1.2.3.
The SBOM should be versioned alongside the artifact. Use git to track SBOM changes.
git add ./sbom-cyclone-dx.json
git commit -m "Update SBOM for release v1.2.3"
git push origin main
To enforce consistency, include a Makefile:
.PHONY: build-sbom
build-sbom:
syft -o cyclone-dx-json \
--file-format cyclone-dx-json \
--output sbom-cyclone-dx.json \
docker-image:myapp:$(VERSION)
@echo "SBOM generated for $(VERSION)"
@echo "Generated at $(shell date)" >> sbom-cyclone-dx.json
The --output flag can write directly to a versioned path:
syft -o cyclone-dx-json \
--output ./sboms/myapp-$(VERSION).json \
docker-image:myapp:$(VERSION)
The --output option also supports templating, enabling automatic versioning across multiple artifacts.
An SBOM should be generated during every build and stored with the artifact. This integration ensures traceability and enables downstream security checks.
In a GitHub Actions workflow:
- name: Generate SBOM
run: |
docker run --rm -v ${{ github.workspace }}:/app \
ghcr.io/chainguard/syft:latest \
-o cyclone-dx-json \
--file-format cyclone-dx-json \
--output ./sbom-cyclone-dx.json \
docker-image:myapp:${{ github.ref_name }}
id: sbom
- name: Upload SBOM
uses: actions/upload-artifact@v3
with:
name: sbom
path: ./sbom-cyclone-dx.json
if: always()
The if: always() ensures that the SBOM is uploaded even if the build fails, so that a broken release still includes an SBOM.
The SBOM is then consumed in later steps. For example, a vulnerability scan step uses the SBOM to cross-reference components against known vulnerabilities.
Use grype to perform vulnerability analysis using the SBOM.
grype -o json \
--input ./sbom-cyclone-dx.json \
--output ./vulnerabilities.json
grype queries a local or remote vulnerability database (e.g., nvd, redhat, alpine) and outputs a JSON report with:
CVE-2023-4567)High, Critical)The --input flag is critical: without it, grype scans the artifact directly, missing the SBOM’s full dependency graph.
A common failure is using grype with a --input that lacks externalReferences or purl (Package URL) fields. When purl is missing, grype cannot resolve the correct vulnerability feed. The purl field is not optional—it must be present in the components array.
Embed the SBOM directly into the artifact. For Docker images, use --sbom in docker build.
docker build \
--tag myapp:v1.2.3 \
--sbom \
--build-arg SBOM_OUTPUT=../sbom-cyclone-dx.json \
.
This command:
org.cyclonedx.sbomThe --sbom flag enables SBOM generation by default, using syft under the hood. The --build-arg SBOM_OUTPUT sets the output path, which is used by the docker build process.
To verify the SBOM is embedded, inspect the image:
docker inspect myapp:v1.2.3
Look for the Labels section:
{
"org.cyclonedx.sbom": "true",
"org.cyclonedx.sbom.path": "/app/sbom-cyclone-dx.json"
}
Then extract the SBOM:
docker run --rm \
-v ${PWD}/sbom.json:/output.json \
-w /app \
myapp:v1.2.3 \
cat /app/sbom-cyclone-dx.json > /output.json
In production, the SBOM serves as a source of truth for software inventory and provenance. It enables automated compliance checks, incident response, and rollback validation.
Deployments should include SBOM verification.
docker run --rm \
-v ./expected-sbom.json:/expected.json \
-v ./current-sbom.json:/current.json \
ghcr.io/chainguard/syft:latest \
--compare \
/expected.json \
/current.json
The --compare flag computes the difference between two SBOMs:
The output includes a summary and a detailed diff:
{
"changes": [
{
"type": "added",
"component": {
"name": "fastapi",
"version": "0.95.0",
"purl": "pkg:pypi/[email protected]"
}
},
{
"type": "updated",
"component": {
"name": "requests",
"oldVersion": "2.31.0",
"newVersion": "2.32.0"
}
}
]
}
A silent failure occurs when the SBOM is generated but not validated before deployment. An SBOM may contain invalid JSON, missing purl fields, or inconsistent versioning. The deployment proceeds successfully, but the SBOM is unusable for audits or vulnerability analysis.
When a security incident occurs, the SBOM enables rapid root cause analysis.
In a Kubernetes cluster, use kubectl to extract SBOMs from all deployed images.
kubectl get pods -o wide \
| awk '{print $1}' \
| tail -n +2 \
| xargs -I {} sh -c '
echo "Pod: {}";
kubectl exec {} -- sh -c "cat /app/sbom-cyclone-dx.json" \
> sbom-{}.json
'
Then, use jq to analyze the SBOMs:
jq -r '.components[] | select(.name == "express") | .version' sbom-*.json
This reveals which version of express is deployed across the cluster, enabling targeted patching.
purl: Components lack purl, causing tools to fail to resolve vulnerabilities or metadata.version format: 1.2.3, v1.2, 1.2.3-beta, and 1.2.3-rc1 are all valid, but tools expect a standard format. Mixing formats causes mismatches.An SBOM implementation is not complete until the SBOM is generated, validated, versioned, embedded, and consumed. The most common failure is generating an SBOM and then forgetting it.
This page was rewritten on 16 October 2026. It replaced a templated version that was not specific to its own title. How these pages are written and checked. If anything here is wrong, tell us at [email protected] and we will correct it.
We use cookies for analytics (Google Analytics) and advertising (Google AdSense) to improve your experience and support free content. Privacy Policy