Skip to main content

What the check does

Flags container images referenced by a mutable tag instead of an immutable @sha256: digest, across the three places a workflow pulls an image:
  • a job-level container: (scalar image:tag or a mapping with image:)
  • a services.<name>.image
  • a step uses: docker://image:tag
Images whose value is a pure expression (${{ ... }}) are skipped — the reference isn’t knowable statically.

Why it matters

A tag such as :latest or :18 is a moving pointer. The registry (or an attacker who compromises it, or the publishing account) can repoint that tag to a different image between runs. Your workflow then pulls and executes code you never reviewed — often with repository secrets and a writable token in scope. This is the container-image analog of CICD-SEC-3 unpinned actions. Pinning by digest makes the reference content-addressed: the bytes can’t change without the digest changing.

Vulnerable example

Safe alternative

Resolve a tag to its digest with docker buildx imagetools inspect <image>:<tag> (or crane digest), and keep the digest current with Dependabot or Renovate, both of which update digest-pinned images.