Floating tags like latest are mutable — the same tag can silently deliver a different, compromised image on the next build. An attacker who poisons an upstream image layer (CWE-1357, supply-chain attack) gains code execution in your container without triggering any diff in your repository. NIST 800-53 CM-14 and SLSA L3 both require provenance guarantees that floating tags cannot provide. CIS Docker Benchmark 5.31 flags this as a supply-chain control. SHA-256 digest pinning is the only mechanism that makes each build deterministic and independently verifiable.
Critical because a poisoned base image executes attacker-controlled code in every container instance derived from it, with no application-level defense possible.
Pin every Dockerfile FROM statement to a SHA-256 digest. Retrieve the digest from Docker Hub's tag detail page or with docker inspect --format='{{index .RepoDigests 0}}' <image>. Update Dockerfile:
# Before
FROM node:20-alpine
# After
FROM node:20-alpine@sha256:d4b15b3d48f42059a15bd659be60afe21762aed87f80a581e029b26d60e0e0e0
For minimal attack surface, prefer distroless bases: FROM gcr.io/distroless/nodejs20-debian12@sha256:.... Automate digest refresh with Dependabot or Renovate so pins stay current without manual tracking.
ID: infrastructure-hardening.container-image-security.from-official-pinned
Severity: critical
What to look for: Enumerate every FROM statement across all Dockerfiles in the project. For each FROM, classify it as: (a) official image with digest pin, (b) official image without digest pin, or (c) unofficial/untrusted image. Count the total FROM statements and how many are properly pinned.
Pass criteria: Every FROM statement across all Dockerfiles references an official or trusted base image pinned with a SHA-256 digest (e.g., FROM node@sha256:abc123... or FROM gcr.io/distroless/base@sha256:...). No floating tags such as latest, main, or bare version numbers are used — 100% of FROM statements must be pinned. Report the count: "X of Y FROM statements are digest-pinned."
Fail criteria: Any FROM statement uses a floating tag (latest, main, version without digest) or references an unofficial/untrusted image source without digest pinning.
Do NOT pass when: Only some FROM statements are pinned while others use floating tags — all must be pinned for pass.
Skip (N/A) when: The project does not have a Dockerfile or container images.
Cross-reference: Image scanning in image-scanning check verifies the scanned image matches the pinned digest.
Detail on fail: Name the Dockerfile stages and their FROM statements. Example: "Dockerfile stage 'builder' uses 'node:20' without digest. Stage 'final' uses 'distroless/nodejs' without digest pinning."
Remediation: Floating tags allow image content to change unexpectedly, introducing supply chain risk. Pin all base images with their SHA-256 digest in Dockerfile:
# Instead of: FROM node:20-alpine
FROM node:20-alpine@sha256:abc123def456...
# Or use the distroless secure base:
FROM gcr.io/distroless/nodejs20-debian12@sha256:...
Find digests on Docker Hub or your registry's tag details page. This ensures every build gets the exact image version you tested.