SBOMVault.ai
← Back to blog
Engineering

Container SBOMs: accounting for the layers you actually ship

May 18, 2026·6 min read·SBOMVault Team

If you ship software in containers, your application's dependency manifest tells only part of the story — often less than half of it. A container image is a stack of layers, and most of what is in it was put there by someone else: a base image, an operating-system package manager, system libraries. An SBOM that captures only your application dependencies is, for a containerized product, dangerously incomplete.

A container is more than your code

When you build a container image, you typically start FROM a base image — an operating system plus a runtime. On top of that you install OS packages, then your language-level dependencies, then your application. The final image contains all of it. That means a complete container SBOM has to account for several distinct layers of components:

  1. OS packages from the base image's package manager (Debian/apt, Alpine/apk, RPM-based distributions).
  2. System libraries present in the base image.
  3. Language dependencies — your npm, PyPI, Go, Maven, or other packages.
  4. Your application code itself.

Scan only layer 3 and you miss the operating-system attack surface entirely — which is exactly where a large share of container vulnerabilities live.

Why the base image is the quiet risk

Base images are convenient and dangerous for the same reason: you inherit everything in them, including their vulnerabilities, often without thinking about it. A months-old base image can carry dozens of known OS-package vulnerabilities that have nothing to do with your code and everything to do with your risk posture.

This leads to one of the highest-leverage practices in container security: prefer minimal base images. Distroless or minimal images contain far fewer packages, which means a smaller SBOM, a smaller attack surface, and fewer vulnerabilities to triage. The cheapest way to reduce your container's vulnerability count is often to stop shipping software you never needed.

Generate the SBOM against the built image

For containers, when and what you scan matters. Generating an SBOM from your source manifest captures your application dependencies but none of the OS layer. The correct approach is to generate the SBOM against the built image, so the inventory includes everything that actually ships — base image, OS packages, system libraries, and application dependencies alike.

Both major SBOM formats handle this well. A package URL (PURL) can describe a Debian package just as cleanly as an npm package, so a single CycloneDX or SPDX document can represent every layer of the image in one inventory.

Tie SBOMs to image digests

Container images are mutable in practice — the same tag can point to different content over time. Anchor each SBOM to the image's content digest, not just its tag. That way the SBOM unambiguously describes one specific, immutable image, and you can always answer "what was in the exact image we deployed?" rather than "what was in whatever the tag pointed to that day."

Putting it together

A solid container SBOM practice looks like this:

  1. Start from a minimal base image to shrink the inventory and the attack surface.
  2. Generate the SBOM against the built image, capturing OS packages and application dependencies together.
  3. Anchor it to the image digest so it describes exactly what you deployed.
  4. Scan and re-scan — a container that was clean at build time accumulates vulnerabilities as new CVEs are disclosed against packages it already contains.

The mental shift is the important part. Your container is not your code; it is your code plus an operating system plus everything in between. An SBOM is only honest if it accounts for the whole stack you actually ship.