SBOM for containers: generate it during the build or after?

SBOMcontainer securityCI/CDsupply chain

A plain-language guide to making SBOM useful during a CVE incident: find the vulnerable package, identify the affected image, and know what needs to be rebuilt

The goal is not to “have an SBOM”

SBOM is often treated like one more file for compliance. Generate JSON, upload it somewhere in CI, and the checkbox is done. But during an incident, that file either helps the team move faster or it becomes another thing to search through.

Imagine a simple case: a CVE alert says one package is vulnerable. The team opens SBOM and finds the package name. Then the real questions start:

  • which container image contains it;
  • whether that image is running in production;
  • which commit produced it;
  • who owns the service;
  • whether the fix is in the app dependency, the base image, or both.

If SBOM cannot help answer those questions, it is a list, but it is not yet an operational tool.

SBOM in plain words

SBOM is a list of what the application or container is made from. Think of it like an ingredient label: libraries, system packages, tools, transitive dependencies, and other pieces that ended up inside the final result.

For security work this matters because a CVE alert rarely says, “service X is broken.” It usually says, “package Y is vulnerable.” The team then has to find whether that package exists in any image and where.

Build-time SBOM: source context is clear

Build-time SBOM is created while CI builds the application. At that point, it is easy to connect the result to source code, package-lock.json, pnpm-lock.yaml, Dockerfile, build settings, and commit.

This helps when you need to understand where a dependency came from. In a Node.js app, for example, you can see whether the vulnerable package was added directly or came through another library.

The weakness is that build-time SBOM may not see everything inside the final container. The base image can bring system packages. The Dockerfile can add tools. Later build steps can change the image.

So build-time SBOM answers: “what did we intend to build, and where did that dependency come from?”

Post-build SBOM: the final image is clear

Post-build SBOM is created from the finished container image. It looks at the result, not only the plan. That makes it useful when the alert is about a base image or a system package.

The weakness is context. If post-build SBOM is not tied to a commit, CI run, and image digest, it becomes a snapshot without a story. You can see the package, but not who should fix it or which version should be rebuilt.

So post-build SBOM answers: “what is actually inside this container?”

What most teams should start with

For practical incident response, most teams need both:

  • build-time SBOM explains where dependencies came from;
  • post-build SBOM shows what is really inside the image;
  • the image digest connects both files to a specific release.

This does not have to be a heavy platform. A good first version can be just two files for every important build:

  • sbom-build.json — what CI sees during the build;
  • sbom-runtime.json — what the finished image contains.

The important part is storing both files together with the image digest and commit SHA. Without that link, people will still have to guess during an incident.

Minimum quality checks

  1. The image is identified exactly

Every SBOM should point to one image digest. The latest tag is not enough: today it points to one image, tomorrow it may point to another.

  1. Direct and transitive dependencies are included

This is especially important for Node.js. Real vulnerabilities often sit in packages that your team did not add directly.

  1. SBOM is generated for every important build

If the image changed but SBOM did not, SBOM is stale. For release images, regenerate it every time.

  1. SBOM is stored where people can find it later

Temporary CI cache is not enough. It may disappear after a few days. Store SBOM as a release artifact next to the image reference.

A 7-step rollout

  1. Pick one service first.
  2. Add build-time SBOM and save it as sbom-build.json.
  3. After the container image is built, add post-build SBOM as sbom-runtime.json.
  4. Store commit SHA, image name, and digest with both files.
  5. Add one simple rule: if digest is missing, the release fails.
  6. Take one real CVE alert or an old security ticket and walk from alert to image.
  7. Measure how long the search took. If it took more than 30 minutes, simplify the process.

Node.js example

A CVE alert arrives: a vulnerable package was found in one of your images.

The first step is not to update everything blindly. First, find where the problem lives.

If the package is in sbom-build.json, check the lock file and application dependencies. The fix may be an npm package update or an update to the library that pulled it in.

If the package is only in sbom-runtime.json, the issue probably came from the base image or a system layer. Then you need to update the base image, scan the finished container again, and rebuild the exact digest that was running.

A healthy process gives a short answer:

  • which package is vulnerable;
  • which digest contains it;
  • which service uses that digest;
  • who owns the service;
  • what needs to be rebuilt.

Anti-patterns to remove early

  • SBOM is generated weekly, while images are released daily.
  • SBOM exists only in temporary CI cache.
  • The team uses latest where it needs a digest.
  • There is build-time SBOM, but no check of the finished image.
  • There is post-build SBOM, but no link back to the commit.

Short conclusion

SBOM is useful when a CVE alert can lead the team from a vulnerable package name to a specific image and owner in minutes.

For most teams, the practical starting point is a small hybrid setup: one SBOM during the build, one SBOM after the image is built, and a required link to the image digest.

Sources

Quick checklist

  • Bind every SBOM to the exact container image digest.
  • Store SBOM as a release artifact, not only in temporary CI cache.
  • Check direct and transitive dependencies.
  • Write down the short path: CVE alert -> SBOM -> digest -> owning team.

Set up SBOM that helps during a CVE incident

Task: help me set up SBOM for container images so it is useful during a real CVE incident. Inputs: - CI platform: - Number of teams or projects: - Where container images are stored: - How many hours the team can spend on first response: - Existing tools that show dependencies: - Security alerts from the last 90 days: Provide: 1) What fits us best: build-time SBOM, post-build SBOM, or both. 2) The minimum checks that make SBOM useful during incidents. 3) A 7-step rollout plan without buying a new service. 4) What the team should do when a CVE alert arrives. 5) A Node.js example: how to tell whether the issue comes from an app dependency or from the base container image. Keep the answer practical, short, and free of unnecessary jargon.