Docker Compose check · low

Unpinned image tags in Docker Compose

An image with the latest tag, or with no tag at all (which means latest), can point at a different build each time it is pulled. Two machines can run different code from the same compose file, and an upgrade can arrive unannounced. The explainer flags this as low. Pin a version tag, or a sha256 digest for an exact, unchangeable image.

$ explain docker-compose.yml
! web uses an unpinned image tag low
line 3
fix: see below
$ 

What the free Docker Compose explainer reports on the risky example below.

Why it matters

`latest` is just a default tag name. It is moved by whoever publishes the image and does not promise compatibility, or even that it is the newest version.

Compose pulls an image when it is missing locally or when you run `docker compose pull`. A new server, a cleared cache or a routine pull can therefore bring a different version than the one you tested.

If a publisher's account or pipeline is compromised, an unpinned tag picks up the replaced image on the next pull. A digest cannot be moved to new content.

Risky and safer docker-compose.yml

Riskydocker-compose.yml
services:
  web:
    image: nginx:latest
    restart: unless-stopped
    mem_limit: 512m
Saferdocker-compose.yml
services:
  web:
    image: nginx:1.27.2
    restart: unless-stopped
    mem_limit: 512m

How to fix it

  • Replace latest or the missing tag with a specific version, e.g. nginx:1.27.2.
  • For an exact image, pin the digest: nginx:1.27.2@sha256:…, using the digest shown by docker images --digests or the registry.
  • Update pins on purpose, with a dependency update tool or a scheduled review, so upgrades are visible in your history.

When it's acceptable

  • Throwaway local experiments where you want whatever is newest and do not care about reproducing the result.

Check your own docker-compose.yml

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

docker-compose.yml

Parsed in your browser. Nothing is uploaded.

Explanation

1 service0 networks0 volumes1 low

Top level

webnginx:latest

  • Docs for image (opens in a new tab)

    Runs the image nginx:latest.

    The latest tag (or no tag) can change under you, so a pull may silently bring a different or compromised version.

    Safer: Pin a specific version tag, or better a digest like image@sha256:....

  • Docs for restart (opens in a new tab)

    Restarts if it stops or after a daemon restart (unless-stopped), but stays down if you stopped it manually.

  • Docs for mem_limit (opens in a new tab)

    Limits memory to 512m. The container is killed if it exceeds this.

Questions

Does image: nginx without a tag use latest?

Yes. A missing tag means latest, so the explainer flags it the same way as an explicit :latest.

Is a version tag enough, or do I need a digest?

A version tag can still be re-pushed by the publisher. A sha256 digest always refers to the same image, so it is the stronger pin; many teams combine both for readability.

Does the explainer check services that use build instead of image?

No. It checks the image key only. Base images in a Dockerfile are checked by the Dockerfile explainer.