Compose service image is not pinned

ID

compose_unpinned_image

Severity

low

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Vendor

Docker

Resource

General Security

Tags

ASVS50:v13.1.1, CWE:1357, reachable, supply-chain

Description

A Compose service names an image that does not say which build will run: no tag at all, an explicit :latest, or a floating tag such as stable, alpine or edge that the publisher re-pushes on every release.

Two machines running the same file then run different code, and so do the same machine before and after a docker compose pull. A build that cannot be reproduced cannot be audited, and an image that changes underneath you is the position a compromised upstream tag needs.

The Dockerfile counterpart is unpinned_version_base_image, and the Kubernetes one is unpinned_container_image, and the two of them share one definition of "pinned". The Dockerfile rule reaches the same verdict on the shapes a FROM normally takes, but it parses the reference differently — it reads the port of registry.local:5000/img as a tag — so the three are not guaranteed to agree on a registry with a port.

Examples

Reported:

services:
  cache:
    image: redis:latest
  search:
    image: opensearchproject/opensearch

Not reported — a version number pins at least partially, and a digest pins exactly:

services:
  web:
    image: example/web:1.2.3
  api:
    image: example/api@sha256:9f2b3d2a1c0e4f5a6b7c8d9e0f1a2b3c4d5e6f708192a3b4c5d6e7f8091a2b3c

A service with a build: section is not reported here, with or without an image: key. There the image: value is the tag Compose applies to the image it builds, not a reference it pulls, so there is no upstream to pin and a digest could not be written for it. Its base image is judged by the Dockerfile rules instead.

Mitigation / Fix

Name the version, and prefer a digest where the image is one you did not build:

services:
  cache:
    image: redis:7.2.4
  search:
    image: opensearchproject/opensearch@sha256:9f2b3d2a1c0e4f5a6b7c8d9e0f1a2b3c4d5e6f708192a3b4c5d6e7f8091a2b3c

Keeping the pin current is a job for an update bot rather than a floating tag: the point is that the change is a commit somebody reviewed.

© 2026 Xygeni. All rights reserved