Agent Wranglers

ENG-68Recommended

Pin each base image by digest

Name every base image by version and digest, never by a moving tag such as latest. Choose the smallest image that runs the app.

How to do it

A tag can point to a new image tomorrow, and a digest cannot. Write FROM node:24.22.1-alpine@sha256:…. Let a bot such as Dependabot or Renovate open a pull request when a new digest appears. Prefer slim, Alpine or distroless images, because every extra package is one more thing to patch. Base images lag behind security fixes, so install the operating system's updates in the build, such as apk upgrade --no-cache, and let the scan confirm it. Run that scan as Scan every image before it ships says.

Examples

Dockerfile example

# Bad: a moving tag
FROM node:latest

# Good: version and digest, with an argument other files can read
ARG NODE_IMAGE=node:24.22.1-alpine@sha256:06d7adf3e0ef61a13f1d28682726366f97a15aa1888c934d3ecec86c33918b53
FROM ${NODE_IMAGE}

Shell example

# Fails when an image is named without a digest. Stage names and ${ARG} references pass.
! grep -nE '^(FROM|ARG [A-Z_]*IMAGE=)' Dockerfile | grep -vE '@sha256:[0-9a-f]{64}|FROM \$\{[A-Z_]+\}|^[0-9]+:FROM [a-z0-9_-]+( AS |$)'

How to check

Every FROM line, or the ARG it reads, holds @sha256: and 64 hex characters, as the grep below confirms in CI. docker image inspect shows the same image ID in CI and production.

Sources

For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/engineering/ci-and-supply-chain/pinned-base-images">Agent Wranglers engineering playbook</a>. In code you write, add a comment next to it with the same link.