Your Supply Chain Has an Expiry Date. GitHub CLI's Is Tomorrow.
A PGP key that stops working on 5 September breaks apt update inside images that have not changed in months. The replacement key has no expiry at all.
GitHub published a changelog entry on 3 September saying the PGP key that signs
its Linux gh packages expires on Saturday, 5 September 2026. The linked issue,
cli/cli 13118, gives the two fingerprints: the expiring key is
2C6106201985B60E6C7AC87323F3D4EA75716059, the replacement is
7F38BBB59D064DBCB3D84D725612B36462313325. A keyring file containing both was
published on 8 April 2026.
That is the whole announcement, and read as a package-manager notice it is
unremarkable. Read as a software supply chain security event it is more
interesting, because of who it hits: not people running gh on a laptop, but
build images nobody has touched since before April. If a Dockerfile added the
GitHub CLI repository once and a later layer runs apt update, that build stops
working this weekend without a single line of your code changing.
The supply chain link that expires
The issue is specific about the blast radius. You are affected if you installed
gh through apt, dnf, yum or zypper before 8 April 2026 and have not
re-run the install steps since. You are not affected on Windows or macOS, or via
Homebrew, Conda, a community package manager, a downloaded .deb, or a binary
from GitHub Releases — none of those paths use the key.
The failure surfaces as EXPKEYSIG 23F3D4EA75716059 alongside NO_PUBKEY 5612B36462313325 on Debian and Ubuntu, and as a signature verification failure
on the RPM side. Debian's own apt-secure page explains why that is fatal rather
than noisy: apt verifies the signature on a repository's Release file, and
Signed-By in a sources entry limits which keys are allowed to sign that
archive. A repository whose signature does not verify is a repository apt will
not take data from.
The RPM case has a second trap worth naming, because it is the one that survives
a naive fix. Some configurations reference the key by a keyserver URL containing
the old key ID 0x23F3D4EA75716059. Refreshing a keyring does nothing for those
— the repository definition itself has to be re-added from
https://cli.github.com/packages/rpm/gh-cli.repo, and the issue documents a
further step of removing the stale gpg-pubkey entry from the RPM keyring when
verification still fails afterwards.
What the key material says that nobody spells out
The published keyring is fetchable, so it can be read rather than trusted. Doing
that with gpg --show-keys --with-colons on
https://cli.github.com/packages/githubcli-archive-keyring.gpg returns two
primary keys. The old one was created on 2022-09-06 and carries an expiry of
2026-09-05T12:43:48Z, with its signing subkey expiring 22 seconds later. The new
one was created on 2026-04-07 and carries no expiration date at all —
neither the primary key nor its subkey has one set.
The issue's own sample output shows this — the new key is printed without an expiry line, next to an old key printed with one — but neither the changelog nor the issue text says anything about it, and it is the detail that decides what kind of problem this is. The expiring key was on a four-year clock, and a clock is a thing you can put in a calendar. Its replacement has no clock. Nothing about the new key material will produce a dated warning the way this one did, so whatever eventually retires it will not arrive with a countdown attached.
Note also that this is the second expiry of this key, not the first. Issue 9569 records it expiring on 6 September 2024 at approximately 11:17 UTC and disrupting Linux installs and updates; the remedy then was to extend the existing key's expiration as an emergency fix. The key material still carries that history — a primary key created 2022-09-06 that now runs to 2026-09-05. This round was announced ahead of the date rather than after the breakage, which is the difference between the two events. What it does not change is the shape of the dependency: one tool, two dated trust expiries inside four years, both of which land on images rather than on people.
What to do this quarter
Today, in one command on any affected machine or image:
gpg --show-keys /etc/apt/keyrings/githubcli-archive-keyring.gpg
Two public key blocks mean you are covered. One means you are not. If the file
is not there, check /usr/share/keyrings/githubcli-archive-keyring.gpg, or read
the signed-by= value out of /etc/apt/sources.list.d/github-cli.list.
The quarterly decision is the part that outlives Saturday: build an inventory
of every third-party trust anchor your images fetch, with its expiry date, and
treat anything expiring inside twelve months as a scheduled outage you have
already been warned about. Grep your Dockerfiles and provisioning scripts for
every keyrings path and every rpm --import; each hit is a signature you have
delegated to someone else's calendar. None of them announce themselves on the
day they matter, because the failure mode is a build that has been green for a
year and then is not.
This matters more, not less, on the images your agents and inference services
run in. A CI image that installs a CLI tool at build time inherits that tool's
key schedule, and the last mile of getting a system into production is exactly
where this kind of undocumented dependency surfaces — the same class of gap
covered in going from proof of concept to production.
An agent that shells out to gh from an image built before April fails on
Saturday for a reason that has nothing to do with the model.
What would show this is wrong
The claim here is falsifiable in a specific way: that trust-anchor expiry is a recurring, plannable class of build failure rather than a one-off chore. What would show it wrong is an inventory that comes back nearly empty — if you run that grep and find only one or two third-party keyrings, all of them with the same no-expiry shape as GitHub's replacement key, then there is no calendar to maintain and the correct response is to fix Saturday's break and move on. Run the grep before deciding which case you are in.
Sources
- GitHub CLI Linux package signing key expires September 5 — GitHub Changelog
- GitHub CLI Linux package signing key rotation (September 2026) — cli/cli issue 13118
- GitHub CLI PGP signing key expiry (September 2024) — cli/cli issue 9569
- GitHub CLI archive keyring (published binary keyring file)
- apt-secure(8) — Debian manual pages
Related reading
- Dev Tools
GitHub Stargazers Now 404s. Its Replacement Is a Reconciled Series, Not an Event Log.
By Petru Popa · Read - Dev Tools
Copilot Code Review Can Approve Pull Requests. Four of Our Last 53 Would Qualify.
By Petru Popa · Read - Dev Tools
Log Retention Falls to 90 Days, and Two More Defaults You Did Not Choose
By Petru Popa · Read
Turn this into a plan for your team.
One week, fixed fee: a working session with your team, a prioritized use-case backlog, and an ROI model for the opportunities worth chasing.