ACE Journal

SBOMs in Container Build Pipelines with Syft and Grype

Abstract

Software Bills of Materials (SBOMs) for container images have moved from a compliance checkbox to an operational tool as organizations integrate SBOM generation and vulnerability scanning directly into CI pipelines. Syft, from Anchore, generates SBOMs in both SPDX and CycloneDX formats from container images and filesystem directories. Grype, also from Anchore, matches those SBOMs against vulnerability databases including the NVD, GitHub Advisory Database, and distribution-specific advisories. Running both tools in the build pipeline - and failing builds on policy violations rather than just reporting - converts SBOM generation from documentation into an enforcement mechanism.

Generating SBOMs with Syft

Syft scans a container image layer by layer, identifying installed OS packages (APK, DEB, RPM), language ecosystem packages (pip, npm, Maven, Go modules, Cargo), and executables with embedded version strings. The output formats are CycloneDX JSON (preferred for tooling interoperability) and SPDX JSON (required for some regulatory contexts). Running syft packages <image> -o cyclonedx-json > sbom.json at the end of the build step, before the image is pushed, captures the exact artifact that will be deployed.

For multi-stage Docker builds, scanning the final image misses packages in intermediate layers only if those layers are truly discarded. Syft operates on the final image manifest, which reflects only the layers that ship, making it the correct scan target for runtime risk. Scanning intermediate build images separately - for supply chain traceability rather than runtime risk - is useful for teams under SSDF or executive order 14028 compliance requirements, and Syft supports this via the --from docker source flag against a locally tagged intermediate image.

Vulnerability Matching with Grype

Grype takes an SBOM as input and matches each component against its bundled vulnerability database, which is updated daily and cached locally after the first pull. Running grype sbom:sbom.json --fail-on high exits non-zero if any High or Critical CVE is matched, which makes it a natural pipeline gate. The --fail-on threshold is a policy decision: teams in early adoption typically start at Critical only and tighten to High after establishing a remediation workflow.

Grype’s output includes the matched package, the CVE, the installed version, the fixed version (if available), and the severity. The fixed-version field is the most operationally useful: a CVE with no fixed version in the installed distribution requires a different remediation path (pinning to an alternative package, disabling the vulnerable feature, or accepting the risk) than one where apt-get upgrade suffices.

Integrating into CI and Attaching SBOMs to OCI Artifacts

The standard pipeline integration runs Syft after the image build step and before the push step. The SBOM file is stored as a pipeline artifact for audit purposes and is also attached to the OCI image using cosign attach sbom. This embeds the SBOM as a referrer in the OCI registry, making it retrievable by any tool that understands the OCI referrers API - including Harbor, Zot, and the ORAS CLI. Consumers pulling the image can verify the attached SBOM and run their own Grype scan without re-generating it.

Grype is then run against the SBOM before the push, with results exported as JSON using --output json for ingestion into a vulnerability management platform such as Dependency-Track. Dependency-Track accepts CycloneDX SBOMs and tracks vulnerability state over time per project version, which provides the historical view needed to demonstrate that a vulnerability was known but accepted versus newly introduced.