Skip to content
All writing ‹ Part 08 of 09 · A Golang Upgrade's Chain Reaction
Engineering · 2 min read

An EOL Base Image Silently No-Ops Security Upgrades

apk upgrade on an EOL Alpine branch exits 0, logs nothing, installs zero patches. The Dockerfile looks patched. It is not. The failure mode is a successful command.

apk --update upgrade finished. Exit 0. Clean log. Zero patches installed. The Dockerfile looks patched. It is not. Because alpine:3.20 hit EOL (End of Life, the maintainer stops publishing security patches), the branch stopped receiving updates, so the command ran a successful no-op.

apk --update upgrade Supported (3.22) fetches patches ✓ EOL (3.20) fetches nothing, exit 0 ✗ 3.20 EOL 2026‑04 3.22
Both branches run the same command and both succeed. Only one actually patches.

There is no error to catch. That is the whole danger. The failure mode is a successful command, so nothing in CI, no exit code, and no log line will ever tell you. The only signal is the branch’s EOL date, which lives outside your repo.

  • Alpine supports a release roughly 2 years. Past EOL, a branch gets neither bugfix nor security updates.
  • “Pin to the last-good version” can quietly mean “pin to an EOL distro”. The goals collide. A correctness pin that lands on EOL trades away a real CVE stream (the flow of publicly disclosed security fixes).
  • Prefer a supported release that also meets the correctness constraint. If none exists, the constraint is probably wrong. Re-check the diagnosis.

The most dangerous security gap is not a red alert. It is a green command that ran clean and did nothing.


Sources:

Related: Back to the chain reaction overview, or see pinning with an exit plan and querying the tag matrix.

↑↓ navigate ↵ open esc close