An autonomous hacking agent found a live GitHub admin token in Baseten's infrastructure by pulling a public Docker image and reading its build history. The token was from March 2023, still had repo scope and admin on internal repos in July 2026. The writeup is a good read on its own, but the mechanism it exposes is the part worth internalizing.
The token wasn't in the filesystem layers. It was in the image config: a RUN command had expanded GITHUB_TOKEN directly into history[].created_by. Docker keeps a record of every build step that produced each layer, and that record is downloaded right alongside the image blobs. You can scrub the secret out of the layers, rebuild, even rotate it in the layer — the old build history object still contains the plaintext.
That gap matters for a specific reason. Most cleanup playbooks operate on files: unset the env var, scrub the .env, delete the config. But the threat surface here is metadata, not bytes. A credential that was ever passed through a RUN or ARG on a build machine is effectively immortal in that image's history unless you rebuild from a clean base and never inject it in the first place.
Three things worth doing:
- Treat image build history as part of your audit surface, same as the layers. Secret scanners that only walk filesystem blobs miss it.
- The fix for a leaked build token is rotation plus a rebuild that never passes the secret as a build arg. Rotating a token that lives in an older image's history just leaves a dormant credential on whatever registry still holds that manifest.
- If you hand images to build agents or let agents push to a registry, the credential-routing problem extends to what those images retain in their own history. A container is containment, not a credential boundary, and the boundary leaks through metadata even when the files are clean.
Strix and Baseten handled this well and fast. Worth blocking out 20 minutes to read the play-by-play, because the lesson is cheap now and expensive when it's your build pipeline.
Top comments (0)