All Dockerfile FROM statements use official base images with SHA-256 digest pinning
Why it matters
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.
Severity rationale
Critical because a poisoned base image executes attacker-controlled code in every container instance derived from it, with no application-level defense possible.
Remediation
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.
Detection
-
ID:
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...orFROM gcr.io/distroless/base@sha256:...). No floating tags such aslatest,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-scanningcheck 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.
External references
- cwe · CWE-1357 — Reliance on Insufficiently Trustworthy Component
- nist:rev5 · CM-14 — Signed Components
- slsa:1.0 · L3 — Build with digest-pinned dependencies
- external · CIS-Docker-5.31 — CIS Docker Benchmark v1.6 §5.31 — Do not use the latest tag
Taxons
History
- 2026-04-18·v1.0.0·Initial import from infrastructure-hardening·automated