# Container Image Tag Latest or Missing

> A container image referenced as :latest or with no tag resolves to whatever the registry holds at pull time. Two pods in 1 ReplicaSet can run different code, and a rollback does not roll anything back. ZopNight checks 3 workload kinds.

Source: https://zop.dev/integrations/kubernetes/recommendations/container-image-tag-latest-or-missing
Updated: 2026-08-19

---

## The same manifest, different code

`:latest` is not a version. It is a mutable pointer, resolved when the kubelet pulls, so the
image a pod runs depends entirely on when it started.

That produces the failure mode people find hardest to debug: two pods in the same ReplicaSet
running different builds. One started before the tag moved, one after, both report the same
image string, and they behave differently.

Omitting the tag entirely is identical, since Kubernetes defaults to `:latest`.

## Rollback stops working

This is the consequence that matters most in an incident.

`kubectl rollout undo` restores the previous **pod spec**. If both the current and previous specs
say `myapp:latest`, the rollback restores an identical spec and pulls whatever `latest` points at
now, which is the broken build you are trying to escape.

The rollout reports success. Nothing changed. That discovery, mid-incident, is the argument for
this rule.

## imagePullPolicy interacts badly

With `:latest`, the default pull policy is `Always`, so every pod start re-pulls. That means a
node failure at 3am silently upgrades the rescheduled pod to whatever is newest: an unplanned
deploy triggered by an unrelated event.

With an explicit tag the default becomes `IfNotPresent`, and behaviour is predictable.

## Digests are stronger than tags

An immutable tag is good; a digest is absolute:

```yaml
image: myapp@sha256:abc123...
```

A digest cannot be repointed by anyone. For anything where supply-chain integrity matters, that
is the only reference that guarantees the bytes you tested are the bytes that run.

## Filtering images for latest or no tag

```bash
kubectl get deploy,statefulset,daemonset -A -o json | jq -r '
  .items[] | . as $w | .spec.template.spec.containers[]
  | select((.image | test(":") | not) or (.image | endswith(":latest")))
  | "\($w.kind) \($w.metadata.namespace)/\($w.metadata.name): \(.image)"'
```

## Enforcing it

Tag immutability in the registry stops `latest` moving under you. ECR, GAR and ACR all support
it, and it is off by default in each.
