⏱️ Lectura: 9 min

An artificial intelligence agent took 25 minutes to obtain a GitHub token with administrator permissions over the internal repositories of Baseten, the inference platform valued at $13 billion. The finding was made by Strix, an autonomous pentesting agent, targeting only the *.baseten.co domain, with no credentials and no access to the source code.

📑 En este artículo
  1. TL;DR
  2. Introduction
  3. What happened
  4. Context and history
  5. Technical details and performance
  6. How to test it
  7. Impact and analysis
  8. What’s next
  9. Frequently Asked Questions
    1. What is Strix?
    2. What is a Harbor registry?
    3. Why was a token from 2023 still active in 2026?
    4. What could someone do with that token?
    5. Did Baseten suffer an actual exploitation?
    6. How do I avoid this problem in my own images?
  10. References

The team behind Strix was preparing to hire Baseten as an inference provider. Before trusting it with their own data and their customers’ data, they decided to audit it first. What they found was a GitHub token built into a Docker image from March 2023 that, more than three years later, still granted full access to critical repositories.

TL;DR

  • Strix, the autonomous agent from Strix.ai, obtained a valid GitHub token in just 25 minutes of scanning with no credentials.
  • The token belonged to the basetenbot account and had repo scope, with admin and push access on Baseten’s main repositories.
  • The Docker image containing the token was built in March 2023 and was still active in July 2026, more than 3 years later.
  • The finding started from a public project in a Harbor registry at gcp-us-east4-zlw.registry.baseten.co, with no authentication.
  • The token had admin access to the product’s main repo, the GitOps repo for the clusters, and Baseten’s Homebrew tap.
  • Baseten confirmed the finding as critical, blocked the registry project, and rotated the token the next day.
  • Strix also found AWS keys in the same image, but they were already revoked (InvalidClientTokenId).
  • The token wasn’t in the image’s filesystem but in the history[].created_by field of its configuration.

Introduction

Strix.ai builds Strix, an autonomous hacking agent designed for continuous pentesting. Before integrating it with Baseten for inference tasks, the team applied its usual practice: scan any external provider before depending on it. They pointed Strix at *.baseten.co in black-box mode, with no prior access and no credentials, exactly as an external attacker would.

Baseten is a serious product: many companies rely on its infrastructure to run models in production. That’s why this finding matters beyond the specific case: it shows how an oversight from a 2023 build pipeline can still be exploitable in 2026, unnoticed until someone deliberately looks for it.

What happened

Strix started with standard reconnaissance: host enumeration, certificate log review, and full mapping of the exposed attack surface. During that process, according to Strix’s own blog post, it found a Harbor registry at gcp-us-east4-zlw.registry.baseten.co.

Harbor organizes container images into projects. One of Baseten’s projects was configured as public. With no token and no authentication, Strix was able to list the repositories, obtain anonymous pull tokens, and download manifests and blobs from the actual images, including one called baseten/baseten-app.

Publicly exposed Harbor container registry
A single public project in Harbor was enough to list and download images with no login. Foto de Shubham Dhage en Unsplash

Before reporting just an exposed registry, Strix needed to prove real impact. It downloaded the image and ran TruffleHog over the layers. The first finding was a pair of AWS keys. A read-only call to sts:GetCallerIdentity returned InvalidClientTokenId: the credential was already dead.

Strix kept looking. It inspected the image’s configuration (not the filesystem layers, but the config JSON that Docker stores alongside the image), and there, in the history[].created_by field, a classic GitHub token showed up. The value came from a RUN command that expanded the GITHUB_TOKEN variable directly during the build.

With a read-only request to GET /user using that token, the response was 200, with the account name basetenbot.

Context and history

The flaw isn’t in Harbor or GitHub: it’s in a very common build pattern. When a Dockerfile uses ARG or ENV to pass a secret and then references it in a RUN, Docker records the full command, with the value already expanded, in the image’s history. Deleting the file containing the secret in a later layer doesn’t help: the history still keeps another copy of the value, accessible with a simple docker history –no-trunc or by downloading the image’s config.

Docker documents this behavior and has offered an alternative for years: BuildKit secrets, which mount the value only during the build step and never write it to layers or to the history (official Docker documentation).

⚠️ Watch out: an ARG or ENV with a secret, followed by a RUN that uses it, gets written into the image’s history even if it never appears in the final filesystem.

The baseten/baseten-app image was built in March 2023, before that pattern was as well known as it is today. The token stayed there, inside a registry that at some point became public, unnoticed for more than three years.

Technical details and performance

The basetenbot token had repo scope, the broadest permission for a classic GitHub token: read and write access to any repository the account could reach. The account belonged to the basetenlabs organization.

Checking permissions repository by repository, always with read-only calls, Strix confirmed admin:true and push:true on the product’s main repository, on the GitOps repository that controls the deployment of Baseten’s clusters, and on its Homebrew tap. It also had read and write access to additional private repositories, including some specific to Baseten customers.

curl -sI -H "Authorization: token $GITHUB_TOKEN" https://api.github.com/user | grep -i x-oauth-scopes

GitHub responds with the X-OAuth-Scopes header listing the exact permissions of a classic token. It’s the same read-only technique Strix used to confirm the token had repo scope before continuing the investigation.

OptionWhen to use itAdvantageLimitation
Classic PAT (repo scope)Old scripts and pipelinesSimple to createBroad scope, no expiration by default
Fine-grained PATSpecific access to particular reposScope limited by repo and permission, mandatory expirationEach repo must be configured explicitly
GitHub App / OIDCCI/CD integrationsShort-lived credentials, no static secretHigher initial setup complexity

How to test it

The same check Strix ran can be run against your own images in minutes:

docker history --no-trunc my-image:latest | grep -iE 'token|secret|key|password'
trufflehog docker --image=registry.mycompany.com/project/my-image:latest

If any line returns a real value, the secret got baked into the build history. The fix is to pass the secret only during the build, without it touching any layer:

# syntax=docker/dockerfile:1
FROM node:20-slim
RUN --mount=type=secret,id=github_token \
    GITHUB_TOKEN=$(cat /run/secrets/github_token) && \
    npm config set //npm.pkg.github.com/:_authToken=$GITHUB_TOKEN && \
    npm install

# build:
# docker build --secret id=github_token,env=GITHUB_TOKEN -t my-app .
💡 Tip: use BuildKit’s –mount=type=secret to pass tokens during the build without leaving a trace in any layer or in the history.

To verify the fix worked: docker history –no-trunc on the new image shouldn’t return any match for the token’s value.

Flow of a leaked token from a Docker image to GitHub
From the public registry to the GitHub token: five steps, 25 minutes. Foto de Rubaitul Azad en Unsplash

Impact and analysis

The severity doesn’t come only from the repo scope, but from which repositories it touched. Admin access to the GitOps repo means being able to push changes that end up deployed to Baseten’s production clusters: a real, not theoretical, supply chain vector. Access to the Homebrew tap would have allowed distributing a modified version of the official CLI to anyone who installed it. Access to specific customer repos adds a risk of exposing data that doesn’t even belong to Baseten.

It’s worth acknowledging the response: Baseten’s security team confirmed the report as critical, blocked the registry project, and rotated the token the following afternoon. It was fast, professional handling, something that doesn’t always happen when a company receives this kind of report.

It’s important to note this wasn’t a malicious intrusion: it was a security audit done before becoming a customer, with immediate responsible disclosure. Strix.ai states that it applies this same scan to nearly all of its providers before depending on them.

What’s next

The case confirms a growing practice among security companies: auditing a provider before signing a contract, not after. When a provider handles third-party data, models, or code, an upfront black-box scan costs little compared to the risk of inheriting someone else’s vulnerability.

It also leaves a recognizable pattern for infrastructure teams: review the visibility of every project in Harbor, ECR, or GCR registries, treat a Docker image’s build history as leak surface just as real as the filesystem, and migrate from long-lived classic tokens to fine-grained tokens or short-lived credentials via GitHub Apps or OIDC.

📖 Summary on Telegram: View summary

Try it yourself: run docker history –no-trunc on your most recent image and confirm no RUN exposes a token in plain text.

Frequently Asked Questions

What is Strix?

It’s an autonomous pentesting agent developed by Strix.ai. It automates reconnaissance, low-risk exploitation, and impact validation against a target, in this case *.baseten.co, with no prior access and no credentials.

What is a Harbor registry?

Harbor is an open source container image registry that groups repositories into projects, each with its own public or private visibility configuration.

Why was a token from 2023 still active in 2026?

Classic GitHub tokens don’t expire by default unless an expiration date is set when creating them, something many teams skip for service tokens like basetenbot.

What could someone do with that token?

Push changes to the product’s main repository, to the GitOps repository that controls the clusters, to Baseten’s Homebrew tap, and read or write to additional private repos, including some specific to customers.

Did Baseten suffer an actual exploitation?

There’s no evidence of that. The finding was part of a Strix audit before hiring Baseten as a provider, reported responsibly and fixed the following day.

How do I avoid this problem in my own images?

Use BuildKit secrets instead of ARG or ENV combined with RUN, scan your images with TruffleHog before publishing them, and replace long-lived classic tokens with fine-grained, expiring tokens or GitHub Apps.

References

  • Strix.ai: original article with the full details of the finding and the API responses.
  • Docker Docs: how to use BuildKit secrets to avoid leaving credentials in the build history.
  • GitHub Docs: managing and expiring personal access tokens.
  • Harbor Docs: official documentation for the open source container registry.

📱 Enjoying this content? Follow @programacion on Telegram for daily tech content in Spanish: quick summaries, fresh content every day. @programacion

Imagen destacada: Foto de Sasun Bughdaryan en Unsplash

Categories: Programación

Andrés Morales

Developer and AI researcher. Writes about language models, frameworks, developer tooling, and open source releases. Covers ML papers, the tech startup ecosystem, and programming trends.

0 Comments

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.