When the Next Log4Shell Drops, SBOMs Decide Which Teams Answer in Minutes and Which Scramble for Days



A container image is mostly software you did not write and cannot see: base-image OS packages, transitive dependencies, and libraries pulled in three levels deep. That is fine until a critical vulnerability lands. When a Log4Shell-class flaw emerges, the question the incident team has to answer is which of our hundreds of deployed images contain this component, and a pile of JSON files scattered across CI buckets does not answer that in the ten minutes before leadership starts asking (Systems Hardening, 2026).

The stakes are not theoretical. Supply-chain attacks cost more than 60 billion dollars globally in 2025, roughly triple the 2021 figure, and the base image is consistently the most neglected part of the chain (MrCloudBook, 2026). A Software Bill of Materials is the inventory that turns a black-box image into something you can actually reason about.

This post walks the full SBOM lifecycle for containers with real commands: generate the inventory, scan it and gate the build, attach it to the image in the registry, monitor it continuously, and keep the alert queue honest. No signing theory, just the working pipeline.

Generate the inventory: what is actually in the image

An SBOM is a machine-readable list of every component in an artifact, with the package name, version, licence, and, once cross-referenced, known vulnerabilities (Jit, 2025). Syft, the open-source generator from Anchore, produces one from a container image, uncovering both direct and transitive dependencies.

# Generate an SBOM from an image, in CycloneDX JSON
syft ghcr.io/org/app:1.4.3 -o cyclonedx-json=sbom.json

# Or emit both standards at once
syft ghcr.io/org/app:1.4.3 \
  -o spdx-json=spdx.json \
  -o cyclonedx-json=sbom.json

The two main formats are not interchangeable. SPDX is the Linux Foundation standard, the native BuildKit output, and the usual choice for legal and compliance audits; CycloneDX is the security-focused format that most vulnerability scanners prefer (Docker, 2026). Pick by use case, or emit both.

The trade-off is that generating an SBOM is the easy part, and the tempting place to stop. An inventory nobody scans or stores is a compliance artifact, not a security control, which is what the next four steps are for.

Scan the SBOM and gate the build

Grype, Syft's companion scanner, consumes the SBOM and cross-references each component against vulnerability feeds from NVD, GitHub, and the distributions, reporting the identifier, severity, CVSS score, and fixed version for every match (Jit, 2025). Wired into CI with a failure threshold, it becomes a gate that blocks high-risk images from ever reaching the registry.

# Scan the SBOM and fail the build on high or critical findings
grype sbom:sbom.json --fail-on high

# Scanning the SBOM is faster than re-scanning the whole image
grype sbom:sbom.json -o table

Scanning the SBOM rather than the image is deliberately faster, because Grype reads a captured inventory instead of re-unpacking every layer, and the same pattern of generating with Syft and failing on critical is exactly how teams keep vulnerable images out of their registries (x-cmd, 2026).

The trade-off is threshold discipline. Set the gate too loose and nothing is blocked; set it too strict on a base image full of unfixable low-severity noise and every build fails, so the threshold has to match what your team can realistically act on.

Attach the SBOM to the image, in the registry

An SBOM saved as a separate file in a CI bucket is disconnected from the image it describes, and the moment that image is promoted to another registry or pulled six months later, there is no reliable way to find the matching SBOM. The fix is to generate it at build time and store it as an OCI attestation, co-located with the image, so pulling the image pulls its SBOM too (Docker, 2026).

# BuildKit attaches the SBOM and provenance as in-toto attestations
docker buildx build \
  --sbom=true \
  --provenance=true \
  --push \
  -t ghcr.io/org/app:1.4.3 .

BuildKit runs a generator (Syft by default) during the build and attaches an SPDX SBOM and SLSA provenance as attestations that travel with the image through every environment (AugmentedMind, 2025). It is worth adding a validation step: an SBOM that lists 12 components for an image you know contains 200-plus packages should fail the pipeline, not pass it (Docker, 2026).

An SBOM that lives in a shared drive or a CI bucket will drift out of sync with the image it was generated from. Co-locating it in the registry as an attestation eliminates that gap: pull the image, and you pull its SBOM and provenance with it (Docker, 2026).

The payoff: answer "are we affected?" without a rebuild

This is where stored SBOMs earn their keep. Once an image's inventory is captured, a newly disclosed CVE can be matched against the components it lists without re-analysing or rebuilding the image at all (Docker, 2026). You update the vulnerability database and re-scan the inventory you already have.

# A new CVE dropped overnight. Refresh the DB and re-scan the stored SBOM.
grype db update
grype sbom:sbom.json -o table

# No rebuild, no re-pull of a running container: the inventory already exists.

This is the difference the opening described. With historical SBOMs on hand, assessing exposure to something like Log4j is a rapid query across your inventory rather than a frantic rescan of every running container (x-cmd, 2026).

The morning a critical CVE lands, the question is which of our images are affected. A team with stored SBOMs answers it with a query in minutes; a team without them re-scans production under pressure and answers in days (Systems Hardening, 2026). Same vulnerability, very different day.

Keep the gate honest with VEX

A raw scan of a real image is often a flat dump of every CVE that ever touched an upstream package, most of which are not actually exploitable in your context. Left unfiltered, that noise trains people to ignore the gate. VEX, the Vulnerability Exploitability eXchange format, records a per-CVE verdict, not affected, fixed, under investigation, so the queue reflects real exploitability rather than raw matches.

# Apply an OpenVEX document so resolved findings are suppressed
grype sbom:sbom.json --vex vex.json --fail-on high

When a VEX statement marks a CVE as fixed or not affected, the scanner filters it out of the active queue automatically, keeping the focus on the single question that matters: is this image actually vulnerable or not (Docker + Aikido, 2026).

The trade-off is that VEX is an assertion someone has to stand behind. A false not-affected verdict hides a real exposure, so a VEX statement should carry a justification and an owner, not just make a red result disappear.

The part worth sitting with

The whole point of an SBOM is to convert a question you cannot answer under pressure into one you can answer with a command. Generate the inventory so the image stops being a black box, scan it and gate the build so known-vulnerable images never ship, attach it to the image in the registry so it never drifts away from what it describes, re-scan it whenever the world learns about a new CVE so exposure is a query rather than a fire drill, and filter it through VEX so the alerts that survive are the ones worth acting on. None of these steps is hard on its own, and each is a few lines in a pipeline. What they add up to is the ability, on the worst morning, to say exactly which images contain the thing everyone is suddenly afraid of, while the teams that only ever generated SBOMs as a checkbox are still grepping through production. The inventory is cheap to keep. Not having it is expensive precisely when you can least afford the bill.

Author note

I am Manjunaathaa, an Associate DevOps Engineer at Frigga Cloud Labs. I work across AWS, GCP, and Azure daily, with GitHub Actions as my deployment backbone. My focus is Proactive Resilience, and an SBOM is proactive resilience in its purest form, because it is the work you do before the CVE lands so that afterwards you are running a query, not a search party. Every practice in this post is something I actually run in production, not something I read about. What changed my mind was watching a Log4Shell-style scramble where the hard part was not patching, it was figuring out where the vulnerable library even lived. Now I generate an SBOM for every image, attach it in the registry so it travels with the artifact, and re-scan the stored inventories on a schedule so a new disclosure is a boring re-run rather than an all-nighter. VEX keeps that queue honest so the team trusts it. Connect with me on LinkedIn → Manjunaathaa.

DevOps, Security, SBOM, Container Security, Supply Chain Security, Vulnerability Scanning, Syft, Grype, CycloneDX, VEX

Post a Comment

Previous Post Next Post