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 isn’t. 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’s 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 isn’t a red alert. It’s 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.

Tags #devops #debugging #docker
// connect

Be brave | Be wise | Be grateful

21 BreakinCode

// elsewhere
LinkedInMedium (lang: en)Life RecordYoutube
wh:~$William Hung· © 2026 Taipei · GMT+8 · Available for collaboration