Dockerfile check · low

Base image pinned by tag but not by digest

A tag such as node:22.11-slim is a label the publisher can point at a different image at any time, and publishers routinely re-push version tags with rebuilt images. A digest (image:tag@sha256:…) identifies the exact content and cannot change. Pinning the digest makes builds reproducible and means a compromised or mistaken re-push of the tag can't change your image.

$ explain Dockerfile
! Tagged base images have no digest (applies to every tagged … low
line 1
fix: see below
$ 

What the free Dockerfile explainer reports on the risky example below.

Why it matters

Tags are mutable. Re-pushing a version tag with OS security patches is normal, which is helpful, but it also means the same Dockerfile can produce different images, and a malicious push to the tag would be picked up by your next build.

A digest is the content hash of the image manifest. When a FROM has both a tag and a digest, the digest decides what is pulled; the tag is kept for readers.

The explainer raises this once per file (low severity), for the first tagged FROM without a digest, and the advice applies to every such FROM.

Risky and safer Dockerfile

RiskyDockerfile
FROM node:22.11-slim
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY src ./src
USER 10001
HEALTHCHECK CMD ["node", "src/healthcheck.js"]
CMD ["node", "src/server.js"]
SaferDockerfile
FROM node:22.11-slim@sha256:<digest of the tag you tested>
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY src ./src
USER 10001
HEALTHCHECK CMD ["node", "src/healthcheck.js"]
CMD ["node", "src/server.js"]

How to fix it

  • Look up the digest of the tag you use, for example with docker buildx imagetools inspect node:22.11-slim.
  • Write it after the tag: FROM node:22.11-slim@sha256:<digest>. Use the multi-platform index digest if you build for more than one architecture.
  • Let Renovate or Dependabot update the digest in pull requests, so you still receive the publisher's patched rebuilds, after review.

When it's acceptable

  • Images where you would rather pick up the publisher's patched rebuilds of a tag automatically and accept that builds are not byte-for-byte reproducible. That is a reasonable trade-off if you have no update bot.

Check your own Dockerfile

The risky example is loaded below. Paste your own file to check it for this and every other Dockerfile rule. It runs in your browser; nothing is uploaded.

Dockerfile

Parsed in your browser. Nothing is uploaded.

Explanation

1 stage8 instructions1 low

Stage 0node:22.11-slim

  • Docs for FROM (opens in a new tab)

    Starts from the base image node, tag 22.11-slim.

    A version tag can be re-pushed to different content; only a digest is immutable. This applies to every tagged FROM in the file.

    Safer: Pin the digest as well (image:tag@sha256:<digest>) and let a bot open pull requests when it changes.

  • Docs for WORKDIR (opens in a new tab)

    Sets the working directory to /app for later instructions and the container. It is created if it does not exist.

  • Docs for COPY (opens in a new tab)

    Copies package.json, package-lock.json from your build context to ./ in the image.

  • Docs for RUN (opens in a new tab)

    Runs npm ci --omit=dev while building the image and saves the result as a new layer.

  • Docs for COPY (opens in a new tab)

    Copies src from your build context to ./src in the image.

  • Docs for USER (opens in a new tab)

    Runs later instructions and the container's process as user 10001.

  • Docs for HEALTHCHECK (opens in a new tab)

    Runs node src/healthcheck.js to check the container is healthy.

  • Docs for CMD (opens in a new tab)

    Sets the default command to node src/server.js. It runs when the container starts, and anything passed to docker run replaces it.

Questions

What is a Docker image digest?

A sha256 hash of the image manifest, written as image@sha256:…. It identifies exact content, so unlike a tag it can never point at a different image.

Do I still need the tag if I pin a Dockerfile base image by digest?

It isn't needed to pull the image, since the digest decides what is used, but keeping it (image:tag@sha256:…) tells readers and update bots which version the digest belongs to.

Won't pinning a digest stop me getting security updates?

Only if nothing updates it. Renovate and Dependabot can propose a new digest when the tag is re-pushed, so you get patched images through a reviewed pull request.