Une clé maîtresse LiteLLM non révoquée mène au détournement de la chaîne de publication

Une clé maîtresse LiteLLM non révoquée mène au détournement de la chaîne de publication

Le 21 octobre 2026, une version piégée de LiteLLM, la passerelle open source très utilisée pour accéder aux modèles d’IA, a été publiée sur PyPI et Docker Hub par le pipeline officiel du projet. L’analyse de cause racine publiée le 23 octobre par LiteLLM remonte à une erreur banale : une clé d’administration poussée par erreur dans un dépôt public en mai, supprimée du fichier mais jamais révoquée. Cinq mois plus tard, cette clé a ouvert à l’attaquant l’accès à un jeton GitHub de propriétaire d’organisation, puis à la chaîne de publication. Une leçon directe pour toutes les équipes qui déploient des agents IA dotés d’identifiants.

L’essentiel
  • Une clé maîtresse d’une plateforme d’agents interne, exposée le 27 mai 2026 dans un dépôt GitHub public, n’a jamais été révoquée.
  • Le 10 octobre, l’attaquant l’a utilisée pour récupérer le jeton OAuth GitHub CLI d’un propriétaire de l’organisation, puis a exfiltré les secrets CI et les jetons de deux autres mainteneurs.
  • Le 21 octobre, il a contourné la protection de branche et publié litellm==1.107.0 (7 wheels PyPI) ainsi que des images Docker compromises.
  • Le code malveillant s’exécute à chaque démarrage de Python, même sans importer LiteLLM, et vole identifiants cloud, clés SSH, secrets CI, clés d’API des fournisseurs d’IA et configurations d’outils de développement IA.
  • Tout hôte ayant installé 1.107.0 doit être considéré comme compromis : désinstaller le paquet ne suffit pas.
Artefactslitellm 1.107.0 (PyPI) · tags Docker v1.107.0, latest, main-latest, main-stable
Fenêtre d’exposition21 octobre 2026, 11:39–14:20 UTC
Dernière version saine connue1.106.2
GravitéCritique — vol d’identifiants

La chaîne d’attaque

LiteLLM a qualifié son analyse du 23 octobre de « source de vérité canonique ». Elle remplace les hypothèses provisoires de l’avis d’incident du 21 octobre. La chaîne tient en sept étapes.

Date (UTC)Étape
27 mai, 18:53Un fichier opencode.json contenant une clé d’administration de la LiteLLM Agent Platform est commité dans le dépôt public LiteLLM-Labs/lite-harness. Il est supprimé trois heures plus tard, mais reste dans l’historique et la clé n’est pas révoquée.
10 octobre, 21:13–21:28L’attaquant appelle l’API de la plateforme d’agents ; une requête de listing des agents renvoie le jeton GitHub CLI d’un propriétaire de l’organisation.
10 octobre, 22:11–22:14Des workflows poussés sur des branches temporaires envoient les secrets CI (dont GH_TOKEN et RELEASE_PLEASE_TOKEN) vers un point de terminaison webhook.site, puis les exécutions sont supprimées.
12 octobreLes secrets de plusieurs dépôts privés sont exfiltrés de la même manière.
21 octobre, 10:08Une modification du workflow de publication, rejetée par la protection de branche, est forcée avec le jeton du propriétaire. Elle permet de construire la version depuis le fork sosie Berri-AI/litellm.
21 octobre, 11:11–11:47Le portail d’approbation de production est validé avec le jeton d’un deuxième mainteneur ; sept wheels 1.107.0 puis les images Docker Hub et GHCR sont publiées.
21 octobre, 11:53–11:54Les traces d’exécution sont supprimées avec le jeton d’un troisième mainteneur.
21 octobre, 12:06 → 14:20Un chercheur d’Upwind Security signale la compromission ; PyPI met le paquet en quarantaine vers 13:23 et les tags Docker sont retirés ou réorientés à 14:20.

Pourquoi une simple clé a suffi

La LiteLLM Agent Platform est un projet expérimental d’agents cloud auto-hébergés qui ouvrent des pull requests. Pour cela, elle détenait non pas un jeton à périmètre restreint, mais le jeton OAuth GitHub CLI d’un propriétaire de l’organisation. Selon LiteLLM, ce type de jeton n’est pas limité en périmètre, est émis après la 2FA et n’est pas soumis à la réauthentification exigée pour les actions sensibles. Compromettre l’agent revenait donc à obtenir les droits de propriétaire.

Deux autres facteurs ont aggravé la situation. Le workflow de publication acceptait désormais un propriétaire de source arbitraire, ce qui a permis de construire depuis un fork sosie. Et la règle d’approbation des releases avait été assouplie la semaine même : deux ingénieurs quelconques suffisaient, au lieu d’un compte dédié lié à un appareil physique.

Analyse de la charge malveillante

Selon l’analyse de Corgea, l’attaquant a ajouté un répertoire cook aux données de construction du paquet. Les wheels installaient ainsi à la racine de site-packages trois fichiers : cook.pth, cook.py et sitecustomize.py. Le source et le tag officiel restaient propres, ce qui rendait la modification invisible dans le code.

Exécution et persistance

Le fichier .pth est exécuté par Python à chaque démarrage de l’interpréteur : le voleur tourne même si LiteLLM n’est jamais importé. sitecustomize.py lance en plus un démon détaché (verrou /tmp/remote_code_loader.lock) qui, toutes les heures, récupère un nom d’hôte depuis un fichier GitHub, télécharge du code Python et l’exécute. Aucun second étage n’a été observé à ce jour.

Ce qui est volé

Mots de passe et cookies de navigateurs, clés SSH, GPG et TLS, identifiants AWS, GCP et Azure (y compris via les services de métadonnées), secrets Docker et Kubernetes, configurations CI, jetons Vault, identifiants de registres de paquets, variables d’environnement et configurations d’outils de développement IA. Spécificité LiteLLM : le code interroge la table des identifiants du proxy, qui contient les clés d’API des fournisseurs de modèles. Les données sont chiffrées (AES-256 et RSA-4096) puis envoyées vers litellm.dev, un domaine sosie du légitime litellm.ai.

Précautions de lecture. L’attaquant n’a pas été identifié. Le nombre de téléchargements et de victimes n’est pas confirmé par LiteLLM. Les détails de la charge proviennent d’analyses tierces (Corgea, citant aussi Microsoft), pas de l’analyse de LiteLLM, qui a renvoyé ses changements de processus à une publication ultérieure. Les sources divergent sur la version corrigée recommandée : vérifiez l’avis officiel avant de mettre à jour. Cet incident est distinct de la compromission de LiteLLM de mars 2026.

Pourquoi c’est important

LiteLLM se situe au cœur des architectures IA : il concentre, par construction, les clés d’API de tous les fournisseurs de modèles d’une organisation. Le compromettre, c’est obtenir un trousseau complet. Mais la leçon dépasse ce projet. Un agent IA qui agit sur vos dépôts détient des identifiants, et ces identifiants deviennent la cible. Un jeton surdimensionné confié à un agent expérimental a suffi à transformer une fuite de configuration oubliée en compromission de la chaîne d’approvisionnement logicielle.

Enfin, la suppression d’un fichier ne révoque rien. Un secret poussé dans un dépôt public doit être considéré comme compromis dès la première seconde.

Lecture MITRE ATT&CK

Les sources ne fournissent pas de correspondance ATT&CK. Le tableau ci-dessous est une lecture indicative de Defensy, fondée sur les comportements décrits.

TechniqueComportement observé
T1593.003 — Search Open Websites/Domains: Code RepositoriesClé d’administration récupérée dans l’historique d’un dépôt public
T1078 — Valid AccountsUtilisation de la clé maîtresse puis des jetons de mainteneurs
T1528 — Steal Application Access TokenVol du jeton OAuth GitHub CLI et des secrets CI
T1567.004 — Exfiltration Over WebhookSecrets CI envoyés vers webhook.site
T1070 — Indicator RemovalSuppression des exécutions de workflows
T1195.002 — Compromise Software Supply ChainPublication de 1.107.0 par le pipeline officiel
T1546 — Event Triggered ExecutionExécution à chaque démarrage de Python via .pth et sitecustomize.py
T1552.005 — Cloud Instance Metadata APIRequêtes vers les services de métadonnées cloud

Recommandations

  1. ImmédiatVérifier l’exposition à 1.107.0

    Cherchez Version: 1.107.0 dans les métadonnées installées, les fichiers cook.pth, cook.py et sitecustomize.py dans site-packages, ainsi que /tmp/remote_code_loader.lock. Contrôlez les images tirées le 21 octobre avec les tags latest, main-latest ou main-stable.

  2. ImmédiatTraiter les hôtes touchés comme compromis

    Isolez-les, arrêtez le chargeur, reconstruisez environnements et images à partir de sources saines en épinglant une version vérifiée (1.106.2 ou une version confirmée saine par LiteLLM) et les images par digest.

  3. ImmédiatFaire tourner tous les secrets exposés

    Clés des fournisseurs d’IA stockées dans le proxy, identifiants cloud, Kubernetes, CI, registres, SSH et outils IA. Examinez CloudTrail et les journaux équivalents à partir du 21 octobre 11:39 UTC, et le trafic sortant vers litellm.dev.

  4. Court termeRéduire les droits des agents IA

    Donnez à chaque agent un compte de service dédié et des jetons à périmètre minimal, jamais le jeton personnel d’un administrateur. Inventoriez les identifiants détenus par vos agents et plateformes d’automatisation.

  5. Court termeRévoquer d’abord, nettoyer ensuite

    Activez la détection de secrets à la source (push protection) et formalisez une procédure : tout secret exposé est révoqué immédiatement, même si le commit a été supprimé.

  6. Moyen termeDurcir votre propre chaîne de publication

    Interdisez aux administrateurs de contourner la protection de branche, figez le dépôt source des workflows de release, vérifiez la provenance et comparez le contenu des paquets avec la version précédente (alerte sur tout nouveau .pth).

  7. Moyen termeÉpingler les dépendances

    Utilisez des fichiers de verrouillage avec empreintes et des images référencées par digest plutôt que des versions flottantes.

L’avis de Defensy

Cet incident n’a rien d’exotique : un secret oublié, un jeton trop puissant, un agent IA mal cloisonné. C’est précisément pourquoi il doit alerter. Les agents IA sont des identités à privilèges et doivent être gouvernés comme tels.

Notre offre Adoption sécurisée de l’IA vous aide à cadrer les droits et les secrets de vos agents et passerelles LLM. Notre équipe SOC, Détection & Réponse peut vous accompagner dans la recherche de compromission et la rotation des secrets.

Références
  1. The attack chain behind the v1.107.0 LiteLLM releaseLiteLLM — O. Jensen, M. Wang — 23 octobre 2026
  2. LiteLLM 1.107.0 PyPI and Docker compromise (cook.pth, sitecustomize)Corgea — 22 octobre 2026, mis à jour le 24 octobre
  3. The Unrevoked Key: Agent Credential to LiteLLM Release HijackCloud Security Alliance Labs — octobre 2026
  4. Leaked LiteLLM master key let attackers hijack the release pipelineThe Hacker News — octobre 2026