The Container Supply Chain: From Dockerfile to Registry to Runtime
A container that runs in production is the endpoint of a long chain: a base image pulled from somewhere, a Dockerfile, dependencies fetched from registries, a build system, a container registry, an admission decision, and finally a node. Each handoff is a trust boundary, and supply-chain attacks target the handoffs rather than the destination — because compromising what you build with is quieter and more scalable than attacking what you run. This piece maps the chain so you can see where the trust is, and where it leaks.
The lesson of the last several years — SolarWinds, the Codecov bash-uploader compromise, a steady drip of malicious packages on public registries — is that attackers moved upstream. Why breach one target when you can poison a dependency, a build tool, or a base image that thousands consume? Containers concentrate this risk: a single popular base image or CI action sits beneath enormous swathes of production.
The links in the chain, and how each is attacked
- The base image.
FROM someimage:latestis unconditional trust in whatever that tag points to today. A compromised or typosquatted base injects malware beneath your app before you write a line. - Dependencies. Every
npm install,pip install, orapt-getduring build pulls code from a registry. Typosquats, dependency confusion, and hijacked-maintainer packages all enter here. - The Dockerfile and build context. A leaked build secret, an injected instruction, or a
COPY . .pulling in something it shouldn't. - The build system. CI runs with credentials and network access; compromise it and every image it produces is tainted at the source, provenance and all.
- The registry. Mutable tags and stolen push credentials let an attacker overwrite a legitimate image with a malicious one bearing the same name.
- The deployment. If nothing verifies what runs, a swapped image at any earlier stage sails through to the node.
Turning implicit trust into verified trust
The defensive theme is the same at every link: replace 'we assume this is fine' with 'we can prove this is what we expect'. Concretely, that is the toolkit from the rest of this series, applied end to end.
- Pin everything by digest. Reference base images and dependencies by immutable content hash, not floating tags, so a rebuild is reproducible and upstream cannot silently change what you consume.
- Curate and proxy the inputs. Pull base images and packages through an internal, scanned registry or proxy rather than directly from the public internet on every build.
- Scan and SBOM at build. Enumerate what went in and store the bill of materials, so a future upstream compromise is a query, not an archaeology dig.
- Sign images and generate provenance. Bind each artifact to its source and builder so tampering after build is detectable.
- Verify at admission. Reject unsigned images or images without valid provenance before they run — the point where all the upstream guarantees are finally checked.
- Harden the build system itself. Ephemeral, isolated build runners with least-privilege credentials, because the builder is the highest-value link in the chain.
FROM alpine:latest
# pinned — exactly these bytes, verified on every pull
FROM alpine@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1 ...
Seeing the chain end to end
No single control secures a supply chain; the security is the chain of custody, unbroken from source to runtime. Digest pinning without signature verification, or signing without admission enforcement, leaves a gap an attacker will find — the assurance is only as strong as its weakest verified handoff.
And chain of custody presupposes an inventory of the chain. Shadow build pipelines, unmanaged registries, and base images no one is tracking are handoffs happening outside your visibility, inheriting none of these guarantees. You cannot secure a supply chain whose links you haven't discovered.
- Search your Dockerfiles for
FROM ...:latestor other floating tags — anything not pinned by digest is unconditional trust in whatever the tag points to today. - Trace one production image back a single link: can you say which build produced it and what base it used? A gap there is an unverified handoff.
Checking one image is a taste; mapping the full chain of custody from source to runtime and finding the unverified handoffs is what our assessment runs for you.