A Software Bill of Materials is a complete, machine-readable inventory of everything in your artifact. Generate one with Syft, in a standard format, and use it to answer "are we affected?" in minutes, not days.
When the next Log4Shell drops, the only question that matters is "do we run the affected component, and where?" Teams without an SBOM spent days grepping build systems to find out; teams with one queried an inventory and answered in minutes. An SBOM is that inventory: a complete list of every component and version in a given artifact, produced at build time when the information is exact.
2021, 11pm: "Log4j has a critical RCE (Log4Shell). Are we affected?"
No SBOM: grep across dozens of repos + transitive trees for days,
never fully sure you found every copy.
SBOM: query the inventory ->
"log4j-core 2.14.1 in 3 services, here they are" -> patch.
An SBOM converts a frantic multi-day hunt into a database query.
Increasingly it's also a customer/regulatory requirement (US EO 14028).Syft inspects source directories or, better, built container images and emits an SBOM in a standard format — CycloneDX or SPDX. Generate it from the final image so it reflects exactly what ships, including OS packages, not just app dependencies. Attach it to the release as an artifact so every build has a matching, retrievable inventory.
# generate an SBOM from the image you actually ship
syft app:1.4.0 -o cyclonedx-json > sbom.cdx.json
# or from source
syft dir:. -o spdx-json > sbom.spdx.json
# two standard formats you'll meet:
# CycloneDX (OWASP) — security-focused, common for vuln workflows
# SPDX (Linux Foundation) — license + provenance focused
# generate from the IMAGE so OS libs are included, not just app deps.An SBOM entry identifies each component precisely: name, version, a package URL (purl) that uniquely locates it in its ecosystem, and often a hash and license. That precision is what makes it queryable and what lets a scanner match components to vulnerabilities without guessing. You rarely read it by hand — tools consume it — but knowing the shape helps you trust it.
// sbom.cdx.json (excerpt) — one component, precisely identified
{
"bomFormat": "CycloneDX",
"specVersion": "1.5",
"components": [
{
"type": "library",
"name": "log4j-core",
"version": "2.14.1",
"purl": "pkg:maven/org.apache.logging.log4j/log4j-core@2.14.1",
"licenses": [{ "license": { "id": "Apache-2.0" } }],
"hashes": [{ "alg": "SHA-256", "content": "b2d..." }]
}
]
}A stored SBOM is not just a record — it is an input. Scan the SBOM against vulnerability feeds continuously (a component with no CVE today may have one next week), and diff SBOMs between releases to see exactly what changed in your dependency footprint. This turns the inventory into ongoing monitoring rather than a one-time snapshot.
# scan an existing SBOM for vulns — re-run daily, no rebuild needed
grype sbom:sbom.cdx.json --fail-on high
# a component clean at build time can become vulnerable later;
# scanning the stored SBOM catches "newly discovered CVE in what we
# already shipped" without touching the build.
# diff two releases to review what entered your supply chain:
syft app:1.4.0 -o json > a.json
syft app:1.5.0 -o json > b.json
diff <(jq -r '.artifacts[].name' a.json | sort) \
<(jq -r '.artifacts[].name' b.json | sort)