NEWSkillSec — elevating AI Skills security from malware detection to capability auditingSkillSecLearn more →
Deep Dive

Container Image Composition Analysis: The Layers Source Scanning Misses

Sectrend Research··4 min read
Three component layers in a container image and what each scan covers
Three component layers in a container image and what each scan covers

A familiar confusion

A team wires SCA into CI, source scanning comes back clean, and then the security team runs an image scanner that reports dozens of high-severity findings. The first reaction from developers is usually that the scanner is wrong.

The scanner is not wrong. The two tools are looking at fundamentally different things.

What is actually inside an image

A typical application image contains three layers of components, different in nature:

Layer one: the base image (OS layer) — whatever you put after FROM on the first line of your Dockerfile. It brings an entire operating system userland: glibc, openssl, bash, coreutils, the package manager itself. This layer usually contains far more components than your application dependencies, and none of them appear in any application manifest.

Layer two: system packages — everything installed during the build with apt-get install or apk add: curl, git, compiler toolchains, assorted runtime libraries. These are often installed for build purposes, never removed, and end up shipping in the production image.

Layer three: language dependencies — the ones declared in package.json, pom.xml, requirements.txt. This layer, and only this layer, is what source-level SCA sees.

So “clean source scan, vulnerable image” is not a contradiction at all: the problem lives in the two layers you did not write but are definitely running.

Why base images concentrate the risk

The issue with base images is not poor quality. It is three structural factors:

Size is attack surface. A full ubuntu:22.04 carries hundreds of packages, the vast majority of which your application never touches — but their CVEs still show up in scans, and still require you to explain or remediate.

Update lag. Writing FROM node:18 looks like version pinning, but the tag floats, and teams often rebuild images only every few months. Security updates to the base image do not automatically reach your production environment.

Inherited invisibility. Your image FROMs another team's intermediate image, which FROMs something else. Components in the final production image may originate from a decision three or four layers upstream, and nobody has looked at the whole chain.

Three governance principles

1. Choose minimal base images with a maintenance commitment.

Distroless, official slim variants, alpine — the criterion is not “which is smallest” but “which has the fewest components while still meeting runtime needs, with a defined security update cadence.” Every package removed is one fewer potential CVE and one fewer unnecessary explanation.

2. Put image scanning in CI, alongside source scanning.

They complement rather than replace each other: source SCA intercepts at dependency intake (earlier, cheaper to fix), image scanning backstops at the artifact level (broader, covers what you never declared). The ideal gate sits after image build and before registry push — at that point you can still rebuild; discovering it after push means a rollback.

3. Manage base image versions centrally.

Rather than every team choosing its own FROM, the organization maintains a set of security-reviewed baseline images that teams derive from. The payoff is most visible during an incident: fix the baseline once and let downstream rebuild, instead of twenty teams each investigating separately.

How deep should the SBOM go

If you deliver an SBOM for a containerized product to customers or regulators, exporting language dependencies alone is insufficient — the recipient expects “what is in this image”, not “what this application declared.”

A complete container SBOM should include: base image identity and digest, the system package inventory with versions, the language dependency tree, and provenance for each layer. Fortunately this is automatable: run composition analysis against the built image in CI, export SPDX or CycloneDX, publish it alongside the image.

One detail worth attention is layer traceability: the same component can appear in multiple layers, with different origins and different remediation paths. An openssl issue in the base image is fixed by changing the base image; one in your application dependencies is fixed by changing a declaration. If the SBOM does not distinguish origin, the recipient cannot tell who should fix what.

From “scan passed” to “composition known”

Containerization turned the deliverable from “a jar file” into “an entire runtime environment”, extending the supply chain boundary down by two layers. Transparency requirements have to follow it down.

Worth emphasizing: this is not only a security question but a licensing one. GPL components in the base image and license obligations attached to system packages travel with the image when it is distributed. A compliance audit that looks only at application dependencies is incomplete in the face of containerized delivery.

---

Further reading: SBOM fields in practice · Configuring SCA gates in CI pipelines · Container image analysis in CleanSource SCA

container securityimage scanningSBOMbase imageSCADevSecOpssupply chain security
Want to see this on your own codebase?Get a Demo

Related

Deep Dive

SBOM Is More Than a Compliance Checklist

Many teams treat an SBOM as a document to hand in. But a valuable SBOM drives decisions — which vulns are exploitable, which dependency to fix first, which license carries risk.