Fuite de clé maîtresse LiteLLM : comment un token GitHub a permis une attaque sur la chaîne d’approvisionnement
Orphée Grandsable
En octobre 2026, la communauté open source a découvert avec stupeur que le populaire gateway LLM LiteLLM avait été victime d’une attaque ciblée sur sa chaîne d’approvisionnement. Un attaque chaîne d’approvisionnement d’autant plus inquiétante qu’elle trouve son origine dans une simple erreur de configuration remontant à mai 2026 : une clé maîtresse (master key) de la plateforme d’orchestration d’agents de LiteLLM avait été accidentellement publiée sur un dépôt GitHub public. Cette clé, jamais révoquée après sa découverte, a permis à un attaquant de dérober un token OAuth GitHub possédant les droits de propriétaire de l’organisation, puis de publier une version malveillante du package Python sur PyPI, Docker Hub et GitHub Container Registry. Cet incident met en lumière les fragilités des pipelines CI/CD modernes et l’importance cruciale de la gestion des secrets et des tokens d’accès.
Dans cet article, nous détaillons la chronologie des événements, les mécanismes d’exfiltration mis en œuvre, le comportement du code malveillant, et surtout les leçons à tirer pour toute organisation utilisant des clés API et des workflows automatisés.
En mai 2026, une clé maîtresse LiteLLM exposée par erreur sur GitHub
Le 27 mai 2026, un développeur de LiteLLM a commité un fichier de configuration dans le dépôt public LiteLLM-Labs/lite-harness. Ce fichier contenait, sans aucune protection, la master key du « LiteLLM Agent Platform », un outil interne d’orchestration d’agents conçu pour interagir avec GitHub via un token CLI OAuth.
L’erreur a été rapidement identifiée : le commit a été force-pushé (réécrit) pour retirer le fichier du dépôt, et les clés exposées ont été marquées comme devant être révoquées. Cependant, selon les déclarations des développeurs Oliver Jensen et Mateo Wang, la révocation effective de la master key n’a jamais été effectuée. Ce défaut de suivi est la racine de la compromission ultérieure.
« L’erreur a été rapidement identifiée, le commit a été force-pushé, et nous avons identifié les clés exposées comme nécessitant une révocation. Cependant, la révocation de la master key n’a pas eu lieu. » - Oliver Jensen et Mateo Wang, LiteLLM
Cette fuite de clé maîtresse sur un dépôt public illustre un scénario trop fréquent : la publication accidentelle de secrets dans un historique Git, même rapidement corrigée, laisse une fenêtre d’exploitation si les credentials ne sont pas immédiatement révoqués et remplacés. En l’occurrence, la clé est restée active pendant près de cinq mois.
Octobre 2026 : l’exploitation de la clé non révoquée compromet l’ensemble du pipeline
Le 10 octobre 2026, un attaquant opérant depuis l’adresse IP 69.48.229[.]143 a utilisé la master key pour accéder à l’Agent Platform de LiteLLM. Cette plateforme était configurée avec un jeton OAuth GitHub (GitHub CLI OAuth token) destiné à permettre aux agents auto-hébergés de soumettre des pull requests sur les dépôts de l’organisation.
Or, ce jeton n’était pas limité en privilèges : il était associé au compte propriétaire de l’organisation GitHub BerriAI. L’attaquant a ainsi obtenu un accès de type owner à tous les dépôts de l’organisation, avec la capacité de modifier les workflows, les secrets et les protections de branches.
Les étapes de l’attaque chronologiquement
Voici la chronologie des actions malveillantes, basée sur les investigations de LiteLLM, de Socket et de Microsoft Security Research :
- 10 octobre 2026, 22h11-22h12 UTC : l’attaquant commite deux workflows malveillants (
.github/workflows/cache.yml) dans des branches éphémères (ci-tmp-*) sur les dépôts internesBerriAI/litellmetBerriAI/litellm-auto. Ces workflows sont conçus pour extraire des tokens OAuth supplémentaires appartenant à deux ingénieurs. Les branches sont supprimées moins de deux minutes après l’exécution. - 21 octobre 2026, entre 10h08 et 11h08 UTC : l’attaquant supprime la protection de branche et modifie le pipeline de release. La source de compilation est redirigée vers un dépôt miroir malveillant nommé
Berri-AI/litellm(tiret au lieu de la majuscule). - 21 octobre 2026, 11h39-11h40 UTC : la version 1.107.0 de LiteLLM est publiée sur PyPI. Docker Hub et GitHub Container Registry (GHCR) suivent à 11h46.
- 21 octobre 2026, 11h53-11h54 UTC : les enregistrements des exécutions de production et de staging sont supprimés.
- 21 octobre 2026, 12h06 UTC : Lidor Machluf, chercheur chez Upwind, découvre la compromission et alerte LiteLLM.
- 21 octobre 2026, 13h23 UTC : PyPI met en quarantaine la version 1.107.0.
- 21 octobre 2026, 14h20 UTC : les tags Docker
v1.107.0,latest,main-latest,main-stablesont supprimés ou repointés vers des images saines.
« En fonctionnement normal, la construction et la publication d’une release nécessitent d’être déclenchées par un ingénieur autorisé, puis approuvées par un compte spécial verrouillé sur un dispositif physique dans nos locaux. Cette restriction avait été assouplie pour permettre des releases plus fréquentes, autorisant deux ingénieurs à déclencher et approuver une release. » - LiteLLM
L’attaquant a ainsi pu utiliser un token volé pour déclencher la release (après avoir redirigé le déploiement vers son dépôt malveillant) et un second token pour l’approuver. Les tokens provenaient des deux ingénieurs ciblés par les workflows du 10 octobre.
Les workflows malveillants : des branches éphémères pour voler des secrets
Les analyses de Socket et de Microsoft ont permis de reconstituer avec précision le fonctionnement des workflows malveillants. Chaque workflow était ajouté via un commit poussé sur une branche ci-tmp-<hex> créée à partir d’un commit légitime récent, afin de ne pas éveiller les soupçons.
Détail des deux workflows
| Workflow | Date du commit | Branche | Endpoint d’exfiltration | Secrets collectés |
|---|---|---|---|---|
| Premier | 10 oct. 2026, 22h11 UTC | ci-tmp-a351cc | webhook[.]site/65a42464... | Token GitHub, clé API Together AI, clé signe App GitHub, secrets workspace Linear… |
| Second | 12 oct. 2026 | ci-tmp-4d8517 | webhook[.]site/4da03473... | En plus du premier : clés Anthropic, OpenAI, AWS Bedrock, Tavily, tenant GitGuardian, Playwright storage state, infos PostgreSQL, Redis… |
Selon Karlo Zanki, chercheur chez Socket :
« Aucun des deux commits n’a été poussé sur une branche qui existe encore. Les deux ont été poussés sur des branches à courte durée de vie nommées
ci-tmp-<hex>, créées, utilisées et supprimées en quelques minutes. C’est pourquoi l’activité ne laisse presque rien dans l’historique ordinaire du dépôt. »
Les workflows étaient déclenchés automatiquement via l’événement on: [push]. Une fois exécutés, ils collectaient un large éventail de credentials, y compris le GitGuardian API key, ce qui aurait permis à l’attaquant de neutraliser les alertes de détection de secrets - un coup particulièrement retors. Le Playwright storage state (état de session de navigateur) exfiltré donnait un accès direct au compte Linear sans mot de passe ni 2FA.
L’exfiltration des données était réalisée vers deux endpoints
webhook[.]sitedistincts. Cette technique, simple mais efficace, permettait à l’attaquant de récupérer les secrets sans avoir à maintenir une infrastructure complexe.
Ce que contient la version malveillante 1.107.0 de LiteLLM
La version malveillante du package Python inclut un code conçu pour s’exécuter automatiquement au démarrage de Python, même si LiteLLM n’est pas importé - un mécanisme d’exécution furtive par le biais de startup files placés en dehors du répertoire de l’application.
Deux composants principaux
- Un module de vol de credentials : il cible les outils de développement (SSH, Git, GitLab), les applications d’IA (clés API OpenAI, Anthropic, etc.), les environnements cloud (AWS Bedrock, variables d’environnement), et les navigateurs web (via le Playwright storage state). Il collecte aussi les tokens de registres de paquets : npm, PyPI, pip, Yarn, Maven, Gradle, Composer, RubyGems, Cargo.
- Une porte dérobée Unix : elle se lance en arrière-plan et, toutes les heures, contacte un serveur C2 pour récupérer et exécuter du code arbitraire. La communication se fait par requête HTTP POST vers
litellm[.]dev/healthcheck, domaine enregistré le 13 octobre 2026.
Les données volées sont compressées et envoyées au même endpoint. L’équipe Microsoft Security Research a souligné que le simple fait de lancer Python dans un environnement infecté déclenchait le code malveillant, même sans importer LiteLLM.
« Ensemble, ces mécanismes ont étendu l’exposition potentielle au-delà des déploiements actifs de LiteLLM : simplement démarrer Python dans un environnement affecté pouvait activer le code malveillant, même si LiteLLM n’était jamais importé. Parce que les fichiers de démarrage résidaient en dehors du répertoire de l’application, supprimer uniquement les fichiers de l’application pouvait laisser les composants malveillants de démarrage derrière. » - Microsoft Security Research
Leçons pour sécuriser vos pipelines CI/CD et vos tokens
Cet incident n’est pas un cas isolé. Il illustre des faiblesses que l’on retrouve dans de nombreuses organisations. Voici les points de vigilance essentiels.
Gestion des secrets et des clés API
- La révocation doit être immédiate et vérifiable. Dès qu’un secret est suspecté d’avoir fuité, il doit être révoqué et remplacé dans la foulée. Ne pas se contenter d’un force-push : celui-ci n’efface pas la donnée de l’historique Git (un clone ultérieur peut encore la contenir).
- Utilisez des outils de secret scanning en continu. Des plateformes comme GitGuardian, truffleHog ou GitHub’s secret scanning permettent de détecter les fuites dès le push. L’attaquant a d’ailleurs volé la clé API de GitGuardian, ce qui montre que ces outils doivent eux-mêmes être protégés.
- Minimisez les permissions des tokens. Le principle of least privilege s’applique aussi aux jetons CI/CD. Un token ne doit jamais avoir un scope plus large que nécessaire. Ici, le token OAuth avait les droits owner sur toute l’organisation, ce qui est manifestement excessif.
Sécurisation des workflows GitHub Actions
- Limitez les triggers aux événements nécessaires. Un workflow déclenché sur
pushsur n’importe quelle branche est une porte ouverte. Utilisezpull_request_targetavec prudence, ou mieux, des conditions sur les branches (branch filters). - Protégez les branches et les environnements. Activez les branch protection rules sur les branches
main,release, etc. Exigez des required reviewers pour les modifications de workflows et de pipelines de release. - Auditez régulièrement les accès. Les tokens et les deploy keys doivent être inventoriés et leur usage revu périodiquement. Un token owner-level qui dort pendant des années est un risque.
Réponse à incident et chaîne d’approvisionnement
- Préparez un playbook de révocation. Savoir exactement quoi faire (et dans quel ordre) quand un secret fuit : révoquer, remplacer, inspecter les logs, notifier les dépendants (utilisateurs du package).
- Utilisez la quarantaine automatique. PyPI a mis en quarantaine la version malveillante en moins d’une heure après le signalement. Les écosystèmes de paquets modernes offrent ces mécanismes, mais il faut les connaître et les activer rapidement.
- Sensibilisez les développeurs. L’erreur humaine est à l’origine de la fuite initiale. La formation aux bonnes pratiques de gestion des secrets (ne jamais les coder en dur, utiliser des vaults, des variables d’environnement) est indispensable.
Extrait d’une checklist de sécurité CI/CD
| Élément | Action recommandée | Priorité |
|---|---|---|
| Clés API en dur dans le code | Utiliser un secrets manager (GitHub Secrets, AWS Secrets Manager, Vault) | Critique |
| Tokens avec scope trop large | Restreindre les permissions au minimum nécessaire (scope repo, contents: write seulement si besoin) | Critique |
Workflows déclenchés sur push sans filtre | Ajouter des filtres de branches (branches: [main, 'release/*']) | Haute |
| Historique Git contenant des secrets | Forcer un rebase ou un git filter-repo, mais surtout révoquer le secret | Haute |
| Absence de branch protection sur les branches de release | Activer les branch protection rules avec required status checks | Haute |
| Pas d’audit périodique des tokens | Mettre en place une revue trimestrielle des accès GitHub, GitLab, etc. | Moyenne |
Conclusion : réagir vite, mais surtout prévenir
L’attaque contre LiteLLM illustre une fois de plus comment une fuite de clé maîtresse sur la voie publique, combinée à un défaut de révocation, peut mener à une compromission complète de la chaîne d’approvisionnement logicielle. En exploitant une simple clé exposée sur GitHub, l’attaquant a pu dérober des tokens à privilèges élevés, modifier le pipeline de release, et distribuer une version malveillante de LiteLLM à des milliers d’utilisateurs.
Les bonnes pratiques de sécurité des secrets et des workflows CI/CD ne sont pas optionnelles. Chaque organisation, même de taille modeste, doit mettre en place des mécanismes de détection, de limitation et de révocation des credentials. La transparence dont a fait preuve LiteLLM dans sa communication post-incident est louable, mais elle ne doit pas masquer le problème de fond : si un secret fuite sur GitHub et n’est pas révoqué, le risque est maximal.
« L’enquête a été un processus au cours duquel nous avons continuellement appris de nouvelles informations, ce qui signifie que certaines de nos hypothèses et croyances se sont avérées inexactes ou incomplètes. » - Oliver Jensen, LiteLLM
En tant qu’équipe sécurité, il ne suffit pas de réagir vite : il faut anticiper. La gestion des clés API et la sécurisation des pipelines doivent être considérées comme des piliers de votre stratégie de sécurité DevSecOps. L’incident LiteLLM de 2026 doit servir d’avertissement à toutes les organisations qui s’appuient sur l’automatisation GitHub et l’écosystème open source.