Attaque LiteLLM : comment une clé maîtresse non révoquée a permis le détournement de la chaîne d’approvisionnement
Lysandre Beauchêne
Une clé exposée pendant cinq mois a suffi : leçons de l’incident LiteLLM
En octobre 2026, la bibliothèque Python LiteLLM a été victime d’une attaque sophistiquée sur sa chaîne d’approvisionnement. L’incident, révélé par l’éditeur lui-même, a conduit à la publication d’une version malveillante (1.107.0) sur PyPI et Docker Hub, compromettant potentiellement des milliers d’environnements de développement et de production. Pourtant, tout a commencé par une erreur apparemment banale : un fichier de configuration contenant la clé maîtresse de la plateforme Agent Platform a été accidentellement commitée sur un dépôt GitHub public le 27 mai 2026. Cette clé, jamais révoquée, a donné à un attaquant les moyens de prendre le contrôle de l’infrastructure de publication. Retour sur les faits, les techniques employées et les mesures de prévention essentielles.
La fuite initiale : une clé maîtresse laissée ouverte
Le commit fatal du 27 mai 2026
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, par inadvertance, la clé maîtresse d’un déploiement de l’Agent Platform, un outil interne d’orchestration d’agents IA. L’erreur a été rapidement identifiée, et le commit a été force-pushé pour le retirer de l’historique. Toutefois, la rotation des clés exposées n’a pas été effectuée pour la clé maîtresse. Cette négligence a laissé une porte ouverte que l’attaquant a exploitée cinq mois plus tard.
« L’erreur a été rapidement identifiée, le commit force-pushé, et nous avons identifié les clés exposées comme nécessitant une révocation. Cependant, la révocation de la clé maîtresse n’a pas eu lieu. »
- Oliver Jensen et Mateo Wang, LiteLLM
Pourquoi la non-révocation est une faille critique
Dans la pratique, bien des équipes retirent un commit compromis sans vérifier que le secret a effectivement été utilisé ou qu’il est encore stocké dans des caches (clones locaux, logs CI, artefacts). Selon les bonnes pratiques de l’ANSSI, tout secret ayant transité sur un support public doit être immédiatement révoqué et remplacé. L’incident LiteLLM illustre tragiquement cette exigence : la clé maîtresse, bien que supprimée du dépôt, restait active sur le serveur de l’Agent Platform et n’avait pas été changée.
De la clé maîtresse au vol de token GitHub : la chaîne d’exploitation
Accès à la plateforme Agent et extraction du token OAuth
Le 10 octobre 2026, un attaquant opérant depuis l’adresse IP 69.48.229.143 a utilisé la clé maîtresse non révoquée pour s’authentifier sur l’Agent Platform. Celle-ci était configurée avec un jeton OAuth GitHub CLI permettant aux agents cloud de soumettre des pull requests sur les dépôts GitHub. Or, ce jeton n’était pas restreint en droits : il était associé au compte propriétaire de l’organisation GitHub. En conséquence, l’attaquant a obtenu un accès complet (owner-level) à tous les dépôts de l’organisation.
Escalade des privilèges et installation de workflows malveillants
Une fois ce jeton en main, l’attaquant a déroulé un plan en plusieurs étapes minutieusement chronométrées :
- 10 octobre 2026, 22h11-22h12 UTC : l’attaquant crée des branches jetables (
ci-tmp-<hex>) sur les dépôts internesBerriAI/litellmetBerriAI/litellm-auto, y pousse un workflow malveillant nommécache.yml, qui exfiltre les jetons GitHub CLI de deux ingénieurs possédant des droits de mainteneur via un endpointwebhook.site. Les branches sont supprimées quelques minutes après l’exécution. - 21 octobre 2026, 10h08-11h08 UTC : après avoir récolté suffisamment de jetons, l’attaquant contourne la protection de branche et modifie le pipeline de publication pour pointer la source vers un dépôt miroir malveillant nommé
Berri-AI/litellm(avec un tiret au lieu du « I »). - 21 octobre 2026, 11h39-11h40 UTC : la version 1.107.0 de LiteLLM est publiée sur PyPI, puis sur Docker Hub et GitHub Container Registry quelques minutes plus tard.
- 21 octobre 2026, 11h53-11h54 UTC : les enregistrements des exécutions des runs de production et de staging sont supprimés pour masquer l’activité.
- 21 octobre 2026, 12h06 UTC : la compromission est détectée et signalée par le chercheur Lidor Machluf de l’entreprise Upwind.
- 21 octobre 2026, 13h23 UTC : PyPI met en quarantaine la version malveillante.
- 21 octobre 2026, 14h20 UTC : les tags Docker Hub (v1.107.0, latest, main-latest, main-stable) sont retirés ou repointés vers des images saines.
Ce schéma montre une exécution rapide et méthodique, avec des fenêtres d’exploitation très courtes. La capacité de l’attaquant à déclencher et approuver la publication était permise par une règle d’approbation détendue : le pipeline, normalement verrouillé par un appareil physique au bureau, avait été assoupli pour permettre à deux ingénieurs de déclencher et approuver une release. L’attaquant, disposant de deux jetons, a simplement joué les deux rôles.
« En fonctionnement normal, la construction et la publication d’une release nécessitent d’être lancées par un ingénieur autorisé et approuvées par un compte spécial verrouillé sur un appareil physique dans nos bureaux. Cette restriction a été assouplie plus tôt cette semaine pour accommoder la poussée temporaire en faveur de publications plus fréquentes et de rétroportages de correctifs, permettant à deux ingénieurs de déclencher et d’approuver une release. »
- LiteLLM
Analyse approfondie des workflows malveillants
Deux commits cachés dans des branches éphémères
La société Socket, spécialisée en sécurité applicative, a publié une analyse détaillée des workflows ajoutés. Selon le chercheur Karlo Zanki, deux commits malveillants ont chacun ajouté un fichier .github/workflows/cache.yml dans le dépôt. Le premier commit date du 10 octobre 2026, le second du 12 octobre. Les deux ont été poussés sur des branches éphémères nommées ci-tmp-<hex> (par exemple ci-tmp-a351cc et ci-tmp-4d8517), créées à partir d’un commit légitime récent pour paraître anodines.
Ces workflows étaient déclenchés automatiquement sur chaque push (on: [push]), ce qui les a exécutés immédiatement. Après exécution, les branches étaient supprimées, ne laissant quasi aucune trace dans l’historique ordinaire.
Données exfiltrées : un panorama complet des secrets
Le premier workflow (10 octobre) collectait :
| Type de secret | Détail |
|---|---|
| Tokens GitHub | Tokens OAuth CLI des ingénieurs |
| Clés API | Jetons pour l’espace de travail Linear, déploiement LiteLLM, Together AI |
| Clé privée d’application GitHub | Identifiant et clé de signature de l’application GitHub |
Le second workflow (12 octobre) étendait la collecte à :
- API Keys : Anthropic, OpenAI, AWS Bedrock, Tavily.
- Clé de scan GitGuardian : l’attaquant pouvait ainsi voir et potentiellement supprimer les alertes qui auraient révélé l’activité malveillante.
- État de session Playwright : stocké en base64, il permet un accès authentifié au compte Linear sans mot de passe ni MFA.
- Informations de base de données PostgreSQL : chaîne de connexion, nom de compte, mot de passe.
- Endpoint Redis : adresse, port, mot de passe.
Les données étaient exfiltrées vers deux endpoints webhook.site distincts :
webhook.site/65a42464-3cfa-4b02-a18c-17a6d7b86f37webhook.site/4da03473-a3e7-4dc2-a087-9c564b4208e1
Karl Zanki de Socket a souligné la gravité de l’exfiltration de la clé GitGuardian :
« GITGUARDIAN_API_KEY est une information d’identification pour la plateforme de secret-scanning elle-même, ce qui donne à un attaquant une visibilité sur, et potentiellement un contrôle des alertes qui auraient révélé cette activité. »
Analyse de la version malveillante 1.107.0 : un double mécanisme de compromission
Plusieurs rapports, notamment ceux de Microsoft Security Research, ont détaillé le fonctionnement du paquet nuisible. Les fichiers livrés avec LiteLLM 1.107.0 étaient conçus pour s’exécuter automatiquement au démarrage de Python, même si l’application n’importait pas LiteLLM. En effet, les startup files placés dans les répertoires système de Python (comme sitecustomize.py ou usercustomize.py) sont chargés à chaque invocation de l’interpréteur.
Le malware comportait deux chemins d’exécution principaux :
Module de vol d’identifiants : il ciblait les fichiers d’authentification des outils de développement (SSH, Git, GitLab), des applications IA, des environnements cloud et des navigateurs web. Il collectait également les variables d’environnement et les jetons des gestionnaires de paquets (npm, pip, Yarn, Maven, Gradle, Composer, RubyGems, Cargo). Les données étaient compressées et envoyées via une requête HTTP POST à
litellm.dev/healthcheck(domaine enregistré le 13 octobre 2026).Porte dérobée Unix : un processus d’arrière-plan était lancé pour récupérer et exécuter du code arbitraire fourni par l’attaquant toutes les heures.
Selon Microsoft Security Research, « le simple fait de démarrer Python dans un environnement affecté pouvait activer le code malveillant, même lorsque LiteLLM n’était jamais importé. Comme les fichiers de démarrage résidaient en dehors du répertoire de l’application LiteLLM, la suppression des seuls fichiers de l’application pouvait laisser les composants malveillants de démarrage derrière. »
Ce mécanisme est particulièrement insidieux : il permet une persistance silencieuse et difficile à détecter par les analyses conventionnelles centrées sur les modules importés.
Leçons pour la sécurité des chaînes d’approvisionnement
Quelles mesures retenir de cet incident ?
L’incident LiteLLM illustre plusieurs failles récurrentes dans les pratiques DevSecOps. Voici les axes d’amélioration prioritaires :
- Révocation systématique des secrets exposés : tout secret ayant transité sur un canal public ou un dépôt doit être immédiatement révoqué et remplacé, même si le commit est supprimé.
- Restriction des jetons d’accès : les tokens OAuth doivent être limités aux seules permissions nécessaires (principe du moindre privilège). Un jeton owner-level ne devrait jamais être utilisé par une CI ou un agent. GitHub recommande les fine-grained personal access tokens avec des périmètres réduits.
- Protection des branches et validation stricte : l’attaque a contourné la protection de branche parce que l’attaquant possédait un jeton avec des droits élevés. Il convient d’ajouter des vérifications d’intégrité (signature de commits, exigence de pull requests approuvées) et de ne jamais autoriser de modification de pipeline sans approbation physique.
- Surveillance des activités anormales : les branches éphémères avec des workflows s’exécutant en dehors des heures de bureau auraient pu être détectées par des outils de monitoring des runs CI. L’alerte précoce aurait peut-être permis d’interrompre la chaîne avant la publication malveillante.
- Rotation des clés après un incident : même sans preuve d’utilisation, toute clé ayant pu être compromise doit être remplacée. La période de cinq mois entre la fuite et l’exploitation montre que l’attaquant peut attendre le moment opportun.
- Segmentation des environnements : l’Agent Platform ne devrait pas avoir accès à un token GitHub owner-level. L’utilisation d’un service dédié avec des identifiants limités réduit la surface d’attaque.
Un tableau récapitulatif des bonnes pratiques
| Pratique | Description | Exemple concret |
|---|---|---|
| Révocation immédiate | Après toute fuite potentielle, révoquer et remplacer les secrets dans les 24 heures. | L’incident LiteLLM aurait été évité si la clé maîtresse avait été changée en mai 2026. |
| Moindre privilège | Les jetons CI et agents doivent avoir uniquement les permissions nécessaires. | Utiliser des tokens fine-grained avec lecture seule sur les dépôts ciblés. |
| Protection des pipelines | Restreindre les déclencheurs de release à des dispositifs physiques ou à une validation multi-facteurs. | Imposer une validation par un appareil physique ou une MFA matérielle. |
| Surveillance proactive | Analyser en continu les exécutions CI, les branches éphémères et les modifications de workflows. | Configurer des alertes sur les nouvelles branches créées par des utilisateurs non humains. |
| Scan des secrets dans les dépôts | Utiliser des outils comme GitGuardian ou TruffleHog pour détecter les fuites en amont. | Mettre en place un scan automatique à chaque push. |
| Rotation périodique | Même sans incident connu, renouveler régulièrement les clés d’infrastructure. | Suivre les recommandations de l’ANSSI (rotation tous les 90 jours pour les clés sensibles). |
Vers une résilience accrue des chaînes d’approvisionnement logicielles
L’attaque LiteLLM n’est pas un cas isolé. Les incidents touchant les bibliothèques open source se multiplient : codecov en 2021, SolarWinds en 2020, log4j en 2021. En 2026, la menace des chaînes d’approvisionnement est devenue structurelle. Les entreprises doivent adopter une approche défensive en profondeur :
- Authentification forte : toujours utiliser des tokens avec des durées de vie courtes et les renouveler automatiquement.
- Détection des anomalies : implanter des sondes dans les pipelines CI/CD pour identifier les comportements suspects (branches éphémères, exécution hors horaire, changements de configuration).
- Réponse aux incidents : disposer d’un plan de réponse prêt à être exécuté, incluant la révocation massive de secrets et la communication aux parties prenantes.
- Audit externe : faire analyser régulièrement sa posture de sécurité par des experts indépendants (tests d’intrusion, revue de code).
Enfin, la communauté open source doit renforcer ses mécanismes de gouvernance. Comme le souligne la publication de LiteLLM, « la divulgation des failles est un processus dans lequel nous apprenons continuellement de nouvelles informations, ce qui signifie que certaines de nos hypothèses et croyances se sont révélées plus tard inexactes ou incomplètes. » Cette humilité face à la complexité des systèmes modernes doit nous inciter à ne jamais sous-estimer l’importance d’une hygiène de sécurité rigoureuse.
Conclusion : une fenêtre de cinq mois qui aurait pu être fermée
La compromission de LiteLLM démontre qu’un seul secret non révoqué peut anéantir des mois d’efforts de sécurisation. Le 27 mai 2026, une clé maîtresse est exposée. Le 10 octobre 2026, elle est utilisée pour voler des jetons GitHub et détourner le pipeline de publication. Entre-temps, rien n’a été fait pour la révoquer. La leçon est claire : toute exposition de secret, même brève, exige une rotation immédiate et sans exception. Les équipes de sécurité doivent intégrer cette règle dans leur politique de réponse aux incidents, et les développeurs doivent être sensibilisés aux risques des commits intempestifs.
Pour les organisations qui utilisent LiteLLM ou d’autres bibliothèques critiques, il est recommandé de vérifier les versions installées, de mettre à jour vers une version non compromise et de révoquer tous les secrets qui auraient pu être exposés via des environnements contenant la version 1.107.0. La chaîne d’approvisionnement n’est aussi forte que son maillon le plus faible - et ce maillon est souvent une clé oubliée dans un fichier de configuration.