Build1 publisher2 min readPublished
Strix's agent read Baseten's image config and found a live GitHub admin token from March 2023
The credential was in history[].created_by, expanded there by a RUN command that took a build argument, inside a Harbor project anyone could pull anonymously. Baseten rotated it about 17 hours after the disclosure email.
The Engineer · Build desk

What happened
- Strix, evaluating Baseten as a vendor, pointed its autonomous pentesting agent at *.baseten.co with no credentials and no source code before handing over its own code and models.
- About 25 minutes in, the agent surfaced a live GitHub personal access token for an account called basetenbot.
- Before that, the agent found AWS keys in the baseten/baseten-app image, tested them with a read-only sts:GetCallerIdentity call, got InvalidClientTokenId back, and carried on.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- capability The whole chain, recon through anonymous pull through scope confirmation, ran unattended with a free open-source tool, so probing a stranger's registry no longer takes a skilled operator's time.
- constraint A green result from a scanner that only walks filesystem blobs does not cover the image config, so the audit surface teams think they have covered is smaller than the one an attacker downloads.
- decision Anyone who has ever passed a token as a build arg now has to choose between rebuilding images from a clean base and purging old manifests, or accepting a dormant credential on every registry that still serves them.
- precedent A prospective customer ran an unsolicited external test on a vendor's public surface as part of due diligence. Vendors will be measured against that expectation during evaluation.
The pattern that leaked it is five lines of Dockerfile [16]. A token arrives as a build argument, and a `RUN` command expands it inside a shell so `git config` can rewrite GitHub URLs for a private dependency [12]. Two documented behaviours do the damage from there. Docker warns that build arguments can end up in the image's metadata, and here the shell expansion wrote the literal token into the `RUN` entry of `history[].created_by` in the image config [13][8]. `git config --global` also writes the authenticated URL, token included, into `.gitconfig` inside a layer, so the secret exists twice, and deleting the credentials file leaves the history copy [14].
Most scanners miss that second copy. The config blob comes down alongside the image and records every build step, so a secret can sit in the layers, in the history, or both, and most setups walk the filesystem only [15]. According to a second dev.to writeup on the incident, you can scrub the layers, rebuild, and rotate, and the old build history object still contains the plaintext [18]. Rotation without a rebuild that never passes the secret leaves a dormant credential on whatever registry still serves that manifest [19].
The exposure ran from March 2023 to July 2026, about 40 months [4][17][21]. The agent needed roughly 25 minutes and no credentials [2][3]. Strix's own writeup, which both posts reconstruct, says the token was never exploited in that time [25][4].
Twenty-five minutes is Strix's number against Strix's target. The registry project was readable with no token, so the agent could list repositories, mint anonymous pull tokens, and fetch manifests and blobs [6]. The image config still held the expanded `RUN` line [8]. The credential's scope had survived three years: `repo`, in the `basetenlabs` organization, with admin and push on the product repo, on `flux-cd`, and on `homebrew-tap`, confirmed repository by repository with read-only requests [10]. Break any one of those and the chain ends where the AWS keys ended, at an `InvalidClientTokenId` from `sts:GetCallerIdentity` [7].
The response was quick. Reported at 11:10 PM on July 13, the Harbor project was private the next morning, the issue was confirmed critical and the token rotated by 4:34 PM, and the remaining findings were closed by July 17 [11]. From disclosure email to rotation is about 17 hours 24 minutes [22].
The first of the three checks in the dev.to post is `docker history` [24]. For anyone whose builds ever passed a credential as an `ARG`, that copy is still in the history unless the image was rebuilt from a clean base with the secret never injected [20].
What to watch
- Whether Strix publishes enough of the agent run for anyone else to reproduce the 25-minute figure against a different registry.
- Whether secret scanners start parsing the config blob's history[].created_by by default, not just filesystem layers.
- Whether registry operators change the default so new Harbor-style projects are private and anonymous pull is off.