RC RANDOM CHAOS

Baseten lost production GitHub admin in 25 minutes

A 2023 build left a GitHub admin token in a Baseten container image's history. Three years later it still worked, and an AI pentest agent found it in 25 minutes.

· 4 min read
Baseten lost production GitHub admin in 25 minutes

A build step that ran on March 3, 2023 left a GitHub personal access token in the history of a container image. In July 2026 that token still worked. It belonged to an account called basetenbot, and it carried admin and push access to Baseten’s main product repo, the GitOps repo that drives their clusters, and their Homebrew tap, plus read/write on other private repositories including per-customer repos.

Strix, an autonomous pentesting agent built by strix.ai, found it in about 25 minutes. The company runs the tool against vendors before trusting them with data, and Baseten (valued at $13 billion) was a candidate inference provider. They pointed Strix at *.baseten.co with no credentials and no source code.

The path from a public registry to admin

Recon found a Harbor registry at gcp-us-east4-zlw.registry.baseten.co. Harbor groups repositories into projects, and one of those projects was public. Without any token, Strix could list repositories, obtain anonymous pull tokens, and download image manifests and blobs. One of the images was baseten/baseten-app.

An exposed image is not automatically a finding; companies publish images on purpose. So Strix pulled the image to see what was inside. The first hit was a pair of AWS keys, but a read-only sts:GetCallerIdentity call returned InvalidClientTokenId. A dead key.

The live credential was elsewhere. Strix pulled the layers, ran TruffleHog over them, and inspected the image config directly. The GitHub token sat in history[].created_by, the field that records how a build step was created. A RUN command had expanded GITHUB_TOKEN directly into it. A GET /user request with the token returned 200 and the account name basetenbot. Checking scopes returned X-OAuth-Scopes: repo, and the account belonged to the basetenlabs org. Strix verified the repository permissions with read-only requests, confirmed the finding was real, and stopped. It did not clone the customer repo, push, or change anything.

Why the token outlived every cleanup

Where the token lived is the whole lesson. A Docker image has filesystem layers, but it also carries a config blob holding the image’s build history, and that config downloads along with the image. Deleting a credential file from the filesystem does nothing if another copy sits in the build history. This copy survived more than three years there.

How it got there is a familiar pattern. A build needed to fetch private dependencies from GitHub, so someone passed a token in as a build argument. Docker can record that build argument in the image’s metadata and history, and in this case it recorded the actual value. Docker warns about this. There is a second copy of the same problem: git config --global writes the authenticated URL into Git’s config file, so changing how the token enters the build still leaves it baked into the image.

The fix is a BuildKit secret mount with temporary authentication that never persists the credential, plus inspecting both the layers and the history before an image ships. And rotating the old token, because editing the Dockerfile does nothing for an image someone has already pulled.

The access level is worth sitting with. A token that fetches a private dependency needs read on that dependency. This one had admin on the product and deployment repos. Scope a build token to exactly what the build needs and give it an expiry, and a leak like this stays small.

What to check in your own images

  • See what someone can pull from your registries without logging in, including old tags and projects you have not thought about in a while.
  • Read the build history with docker history --no-trunc, or inspect the config blob’s history[].created_by fields. Check the layers too, not just the current filesystem.
  • Get secrets out of build arguments. Use secret mounts, and make sure the commands consuming them do not write them back into the image.
  • Check what your build tokens can actually do. Limit the permissions and set an expiry.

Disclosure

Baseten’s security team moved fast once Strix reported it on July 13 at 11:10 PM. By the next morning they had made the Harbor project private; Strix flagged that the token itself still worked. At 4:34 PM on July 14, Anton from Baseten Security confirmed the issue as critical, said they had rotated the token, and asked Strix to securely delete the pulled images. Strix confirmed deletion at 5:05 PM and sent over two lower-severity findings from the same scan, which Baseten closed out by July 17. In September, Strix told them it planned to disclose publicly and sent a draft of the writeup.

Strix was given a domain and nothing else. If an autonomous agent can walk from a forgotten public registry to a live admin token in 25 minutes, the same path is available to attackers running the same kind of tooling.

Share

Keep Reading

Latest on the Wire

Full wire →

New signal daily · RSS

Stay in the loop

New writing delivered when it's ready. No schedule, no spam.