veilletech.fr
16 sept. Feed du jour
#03 SÉCURITÉ Faille

Un jeton oublié ouvre le GitHub de Baseten

Changer le Dockerfile ne révoque rien : l'image, elle, a déjà été téléchargée.

L'agent de pentest autonome Strix a trouvé, en 25 minutes et sans identifiants, un registre Harbor public sur un sous-domaine de Baseten, puis un jeton GitHub personnel valide dans l'historique de build d'une image. Le jeton du compte basetenbot, de portée repo, donnait admin sur le dépôt produit, le dépôt GitOps des clusters et le tap Homebrew. L'étape de build datait du 3 mars 2023 ; le jeton fonctionnait toujours en juillet 2026.

3 min de lectureintermédiairevidéo 1:15
Partager
Sommaire7 sections
  1. Ce qui se passe
  2. La chaîne, étape par étape
  3. Le motif en cause
  4. Ce que pouvait le jeton
  5. Chronologie de la divulgation
  6. Comment s'y prendre chez soi
  7. À retenir

Ce qui se passe

L'équipe derrière Strix, un agent de test d'intrusion autonome, envisageait d'utiliser Baseten comme fournisseur d'inférence. Avant de lui confier des données, elle a pointé son agent sur *.baseten.co, sans identifiants ni accès au code. Vingt-cinq minutes plus tard, l'agent tenait un jeton d'accès personnel GitHub valide, avec les droits d'administration sur des dépôts internes.

L'étape de construction qui avait enregistré ce jeton datait du 3 mars 2023. Il fonctionnait encore en juillet 2026.

La chaîne, étape par étape

Énumération desous-domaines+ journaux de certificatsRegistre Harborgcp-us-east4-zlw.registry.baseten.coUn projet configuré enpublic jeton de pull anonymeImagebaseten/baseten-appmanifeste + blobstéléchargésCouches du système defichiersclés AWS mortes(InvalidClientTokenId)Config de l'imagehistory[].created_byJeton GitHub en clairGET /user 200,basetenbotX-OAuth-Scopes: repoadmin+push sur 3 dépôts,R/W sur 4 autres

Le détail qui fait la leçon est en bas à droite : le jeton n'était pas dans les fichiers de l'image, mais dans sa configuration, au champ history[].created_by qui enregistre la commande de chaque étape de build. Ce fichier se télécharge avec l'image. Nettoyer un fichier de secrets dans une couche ne sert donc à rien si l'historique en garde une copie.

Le motif en cause

Un build avait besoin de récupérer des dépendances privées depuis GitHub. Le jeton est passé en argument de build, et Docker a enregistré sa valeur :

Dockerfile
ARG GITHUB_TOKEN
RUN GITHUB_TOKEN=${GITHUB_TOKEN} bash -c '\
  if [[ "${GITHUB_TOKEN}" != "" ]]; then \
    git config --global --add \
      url."https://${GITHUB_TOKEN}@github.com/".insteadOf "git@github.com:"; \
  fi'

Deux problèmes se cumulent : l'expansion de la variable dans la commande enregistrée, et git config --global qui écrit l'URL authentifiée dans la configuration Git de l'image. Docker documente explicitement ce risque.

Ce que pouvait le jeton

Compte basetenbot, organisation basetenlabs, en-tête X-OAuth-Scopes: repo, et sur les dépôts :

Dépôt Accès
dépôt du produit principal admin: true, push: true
dépôt GitOps qui pilote les clusters admin: true, push: true
tap Homebrew admin: true, push: true
4 dépôts privés, dont des dépôts par client lecture / écriture

Les chercheurs se sont arrêtés là : aucun clone du dépôt client, aucun push, aucune modification de configuration.

Chronologie de la divulgation

Comment s'y prendre chez soi

  1. Regarder ce qu'un anonyme peut tirer de votre registre, y compris les vieux tags et les projets oubliés.
  2. Lire l'historique de build, pas seulement les couches : docker history --no-trunc <image>, ou inspecter les champs history[].created_by du blob de configuration.
  3. Sortir les secrets des arguments de build, au profit d'un montage de secret BuildKit — et vérifier que la commande qui le consomme ne le réécrit pas dans l'image.
  4. Calibrer les droits : un jeton qui récupère une dépendance a besoin de la lire, pas d'administrer le dépôt du produit. Et lui donner une expiration.

À retenir

Un jeton dans une image publique reste exploitable tant qu'il n'est pas révoqué, quelle que soit la correction apportée au Dockerfile : l'image a déjà été téléchargée. Et si un agent a mis 25 minutes à remonter cette chaîne sans indice, le délai d'exposition n'est plus une notion théorique.