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.