Un agente de inteligencia artificial tardo 25 minutos en conseguir un token de GitHub con permisos de administrador sobre los repositorios internos de Baseten, la plataforma de inferencia valuada en $13.000 millones. El hallazgo lo hizo Strix, un agente autonomo de pentesting, apuntando unicamente al dominio *.baseten.co, sin credenciales ni acceso al codigo fuente.
El equipo detras de Strix se preparaba para contratar a Baseten como proveedor de inferencia. Antes de confiarle datos propios y de sus clientes, decidieron auditarlos primero. Lo que encontraron fue un token de GitHub construido en una imagen Docker de marzo de 2023 que, mas de tres anos despues, seguia dando acceso total a repositorios criticos.
TL;DR
- Strix, el agente autonomo de Strix.ai, obtuvo un token de GitHub valido en apenas 25 minutos de escaneo sin credenciales.- El token pertenecia a la cuenta basetenbot y tenia scope repo, con admin y push en los repos principales de Baseten.- La imagen Docker que contenia el token se construyo en marzo de 2023 y seguia activa en julio de 2026, mas de 3 anos despues.- El hallazgo partio de un proyecto publico en un registro Harbor en gcp-us-east4-zlw.registry.baseten.co, sin autenticacion.- El token tenia admin sobre el repo principal del producto, el repo GitOps de los clusters y el Homebrew tap de Baseten.- Baseten confirmo el hallazgo como critico, bloqueo el proyecto del registro y roto el token al dia siguiente.- Strix tambien hallo llaves de AWS en la misma imagen, pero ya estaban revocadas (InvalidClientTokenId).- El token no estaba en el filesystem de la imagen sino en el campo history[].created_by de su configuracion.
Introduccion
Strix.ai construye Strix, un agente de hacking autonomo pensado para pentesting continuo. Antes de integrarlo con Baseten para tareas de inferencia, el equipo aplico su propia practica habitual: escanear a cualquier proveedor externo antes de depender de el. Apuntaron Strix contra *.baseten.co en modo caja negra, sin ningun acceso previo ni credenciales, tal como lo haria un atacante externo.
Baseten es un producto serio: muchas empresas dependen de su infraestructura para correr modelos en produccion. Por eso el hallazgo importa mas alla del caso puntual: muestra como un descuido de 2023 en un pipeline de build puede seguir siendo explotable en 2026, sin que nadie lo note hasta que alguien lo busca a proposito.
Que paso
Strix arranco con reconocimiento estandar: enumeracion de hosts, revision de logs de certificados y mapeo completo de la superficie expuesta. En ese proceso, segun relata Strix en su blog, encontro un registro Harbor en gcp-us-east4-zlw.registry.baseten.co.
Harbor organiza imagenes de contenedores en proyectos. Uno de los proyectos de Baseten estaba configurado como publico. Sin ningun token ni autenticacion, Strix pudo listar los repositorios, obtener tokens de pull anonimos y descargar manifests y blobs de las imagenes reales, incluida una llamada baseten/baseten-app.
Un solo proyecto publico en Harbor bastó para listar y descargar imagenes sin login.
Antes de reportar solo un registro expuesto, Strix necesitaba probar impacto real. Descargo la imagen y corrio TruffleHog sobre las capas. El primer hallazgo fue un par de llaves de AWS. Una llamada de solo lectura a sts:GetCallerIdentity devolvio InvalidClientTokenId: la credencial ya estaba muerta.
Strix siguio buscando. Inspecciono la configuracion de la imagen (no las capas del filesystem, sino el config JSON que Docker guarda junto a la imagen) y ahi, en el campo history[].created_by, aparecio un token clasico de GitHub. El valor venia de un comando RUN que expandia la variable GITHUB_TOKEN directamente en el build.
Con una peticion de solo lectura a GET /user usando ese token, la respuesta fue 200, con el nombre de cuenta basetenbot.
Contexto e historia
El fallo no esta en Harbor ni en GitHub: esta en un patron de build muy comun. Cuando un Dockerfile usa ARG o ENV para pasar un secreto y despues lo referencia en un RUN, Docker registra el comando completo, con el valor ya expandido, en el historial de la imagen. Borrar el archivo con el secreto en una capa posterior no sirve de nada: el historial sigue conservando otra copia del valor, accesible con un simple docker history --no-trunc o descargando el config de la imagen.
Docker documenta este comportamiento y ofrece una alternativa desde hace anos: los secrets de BuildKit, que montan el valor solo durante el paso de build y nunca lo escriben ni en capas ni en el historial (documentacion oficial de Docker).
⚠️ Ojo: un ARG o ENV con un secreto, seguido de un RUN que lo use, queda escrito en el historial de la imagen aunque nunca aparezca en el filesystem final.
La imagen baseten/baseten-app se construyo en marzo de 2023, antes de que ese patron fuera tan conocido como lo es hoy. El token quedo ahi, dentro de un registro que en algun momento se volvio publico, sin que nadie lo notara durante mas de tres anos.
Detalles tecnicos y rendimiento
El token de basetenbot tenia el scope repo, el permiso mas amplio de un token clasico de GitHub: lectura y escritura sobre cualquier repositorio al que la cuenta tuviera acceso. La cuenta pertenecia a la organizacion basetenlabs.
Al revisar permisos repositorio por repositorio, siempre con llamadas de solo lectura, Strix confirmo admin:true y push:true en el repositorio principal del producto, en el repositorio GitOps que controla el despliegue de los clusters de Baseten, y en su Homebrew tap. Tambien tenia acceso de lectura y escritura a repositorios privados adicionales, incluyendo repos especificos de clientes de Baseten.
curl -sI -H "Authorization: token $GITHUB_TOKEN" https://api.github.com/user | grep -i x-oauth-scopes
GitHub responde con la cabecera X-OAuth-Scopes listando los permisos exactos de un token clasico. Es la misma tecnica, de solo lectura, que uso Strix para confirmar que el token tenia scope repo antes de seguir investigando.
OpcionCuando usarlaVentajaLimitacionPAT clasico (scope repo)Scripts y pipelines viejosSimple de crearScope amplio, sin expiracion por defectoPAT de grano finoAcceso puntual a repos concretosScope acotado por repo y permiso, expiracion obligatoriaHay que configurar cada repo explicitamenteGitHub App / OIDCIntegraciones de CI/CDCredenciales de corta duracion, sin secreto estaticoMayor complejidad de configuracion inicial
Como probarlo
El mismo chequeo que hizo Strix se puede correr sobre las propias imagenes en minutos:
docker history --no-trunc mi-imagen:latest | grep -iE 'token|secret|key|password'
trufflehog docker --image=registry.miempresa.com/proyecto/mi-imagen:latest
Si alguna linea devuelve un valor real, el secreto quedo grabado en el historial de build. La correccion es pasar el secreto solo durante el build, sin que toque ninguna capa:
# 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 mi-app .
💡 Tip: usa --mount=type=secret de BuildKit para pasar tokens en el build sin dejar rastro en ninguna capa ni en el historial.
Para verificar que la correccion funciono: docker history --no-trunc sobre la nueva imagen no deberia devolver ninguna coincidencia con el valor del token.
Del registro publico al token de GitHub: cinco pasos, 25 minutos.
Impacto y analisis
La severidad no viene solo del scope repo, sino de que repositorios tocaba. Admin sobre el repo GitOps significa poder empujar cambios que terminan desplegados en los clusters de produccion de Baseten: un vector de cadena de suministro real, no teorico. Acceso al Homebrew tap habria permitido distribuir una version modificada del CLI oficial a cualquiera que lo instalara. El acceso a repos de clientes especificos suma un riesgo de exposicion de datos ajenos a Baseten.
Vale reconocer la respuesta: el equipo de seguridad de Baseten confirmo el reporte como critico, bloqueo el proyecto del registro y roto el token al dia siguiente por la tarde. Fue un manejo rapido y profesional, algo que no siempre ocurre cuando una empresa recibe este tipo de reporte.
Es importante remarcar que esto no fue una intrusion maliciosa: fue una auditoria de seguridad hecha antes de convertirse en cliente, con divulgacion responsable inmediata. Strix.ai aclara que aplica este mismo escaneo a casi todos sus proveedores antes de depender de ellos.
Que sigue
El caso confirma una practica que va en aumento entre empresas de seguridad: auditar a un proveedor antes de firmarle un contrato, no despues. Cuando el proveedor maneja datos, modelos o codigo de terceros, un escaneo de caja negra previo cuesta poco frente al riesgo de heredar una vulnerabilidad ajena.
Tambien deja un patron reconocible para equipos de infraestructura: revisar la visibilidad de cada proyecto en registros Harbor, ECR o GCR, tratar el historial de build de una imagen Docker como superficie de fuga tan real como el filesystem, y migrar de tokens clasicos de larga vida hacia tokens de grano fino o credenciales de corta duracion via GitHub Apps u OIDC.
📖 Resumen en Telegram: Ver resumen
Probalo vos: corre docker history --no-trunc sobre tu imagen mas reciente y confirma que ningun RUN expone un token en texto plano.
Preguntas frecuentes
¿Que es Strix?
Es un agente autonomo de pentesting desarrollado por Strix.ai. Automatiza reconocimiento, explotacion de bajo riesgo y validacion de impacto sobre un objetivo, en este caso *.baseten.co, sin acceso previo ni credenciales.
¿Que es un registro Harbor?
Harbor es un registro de imagenes de contenedores open source que agrupa repositorios en proyectos, cada uno con su propia configuracion de visibilidad publica o privada.
¿Por que un token de 2023 seguia activo en 2026?
Los tokens clasicos de GitHub no expiran por defecto salvo que se configure una fecha de caducidad al crearlos, algo que muchos equipos no hacen en tokens de servicio como basetenbot.
¿Que podia hacer alguien con ese token?
Empujar cambios al repositorio principal del producto, al repositorio GitOps que controla los clusters, al Homebrew tap de Baseten, y leer o escribir en repos privados adicionales, incluyendo algunos especificos de clientes.
¿Baseten sufrio una explotacion real?
No hay evidencia de eso. El hallazgo fue parte de una auditoria de Strix antes de contratar a Baseten como proveedor, reportado de forma responsable y corregido al dia siguiente.
¿Como evito este problema en mis propias imagenes?
Usa BuildKit secrets en vez de ARG o ENV combinados con RUN, escanea tus imagenes con TruffleHog antes de publicarlas, y reemplaza tokens clasicos de larga vida por tokens de grano fino con expiracion o por GitHub Apps.
Referencias
- Strix.ai: articulo original con el detalle completo del hallazgo y las respuestas de la API.- Docker Docs: como usar BuildKit secrets para no dejar credenciales en el historial de build.- GitHub Docs: gestion y expiracion de personal access tokens.- Harbor Docs: documentacion oficial del registro de contenedores open source.
📱 ¿Te gusta este contenido? Unete a nuestro canal de Telegram @programacion donde publicamos a diario lo mas relevante de tecnologia, IA y desarrollo. Resumenes rapidos, contenido fresco todos los dias.
Top comments (0)