LiteLLM : du secret oublié dans Git à une release malveillante signée
La version 1.107.0 de LiteLLM a distribué un malware via PyPI et Docker. Chaîne d’accès, contournement du pipeline, preuves et réponse à incident.
Publication des artefacts compromis : 21 octobre 2026. Analyse rédigée le 4 novembre 2026. Pendant environ deux heures, litellm==1.107.0 sur PyPI et plusieurs tags Docker de LiteLLM pointaient vers du code malveillant. Le rapport final de LiteLLM montre une chaîne remarquable : secret publié en mai, jeton toujours valide en octobre, accès propriétaire à l’organisation GitHub, modification du workflow de release, puis construction depuis un dépôt ressemblant au dépôt officiel. Le paquet et les images ont été signés par l’infrastructure légitime. La signature prouvait donc le passage par ce pipeline, pas l’innocuité de sa source.
La chaîne de confiance, maillon par maillon
Le 27 mai, un fichier opencode.json contenant une clé administrateur d’une plateforme interne expérimentale a été commité dans un dépôt public. Un commit ultérieur a supprimé le fichier trois heures plus tard, mais la clé n’a pas été révoquée et l’ancien commit est resté lisible dans l’historique. Le 10 octobre, l’attaquant a utilisé cette clé pour interroger l’API des agents gérés. La réponse contenait un jeton OAuth gh appartenant à un propriétaire de l’organisation GitHub de LiteLLM. (Chronologie détaillée)
Ce premier pivot a changé l’échelle de l’incident. Un jeton de propriétaire pouvait déclencher des workflows, pousser sur des dépôts et outrepasser certaines protections. L’attaquant a créé des branches et workflows éphémères pour exfiltrer des secrets de CI, dont deux autres jetons de mainteneurs. Ces actions sont documentées par les traces d’API et de workflows dans le rapport. Elles rappellent que les secrets disponibles à un job peuvent être obtenus par un workflow autorisé à tourner, même si l’attaquant ne peut pas les lire directement depuis l’interface GitHub.
Le 21 octobre, l’attaquant a modifié le workflow du dépôt privé BerriAI/project-releaser. Il a ajouté un paramètre source_owner permettant de choisir l’organisation source. Un push avec un jeton de mainteneur a été refusé par la protection de branche ; le même push avec le jeton du propriétaire a réussi. Le workflow a ensuite construit depuis Berri-AI/litellm, organisation au nom visuellement proche de BerriAI/litellm, puis une seconde identité compromise a validé la porte d’approbation de production. Le tag source officiel v1.107.0 sur GitHub ne contient pas les fichiers malveillants : comparer le tag au paquet PyPI suffit à révéler que la provenance du build a divergé. (Rapport LiteLLM, avis sur les artefacts)
Ce que faisait le paquet et pourquoi la signature ne suffisait pas
Selon LiteLLM, la version compromise contenait du malware compilé qui volait des identifiants et chargeait des outils d’exécution de code distante. Les fichiers cook.pth et sitecustomize.py sont des indicateurs importants : Python peut exécuter du code via ces mécanismes au démarrage de l’interpréteur, avant l’appel voulu par l’utilisateur. Ainsi, lancer pip dans l’environnement infecté peut relancer le code malveillant. Le contenu exact et l’étendue des secrets accessibles dépendent de l’hôte ou du conteneur où l’artefact a été exécuté.
La chaîne de signature n’a pas été cryptographiquement cassée. Le workflow officiel a construit et publié un artefact venant d’une source substituée. LiteLLM précise que les images compromises avaient même une signature valide sous l’ancienne clé Cosign ; l’équipe a ensuite changé cette clé. Vérifier seulement « signature valide » répond à la question qui a signé ? ; il faut aussi vérifier quel commit et quel dépôt ont été construits ? et quel digest exact tourne ?.
Comment on pouvait trouver l’attaque
La première alerte publique est une issue GitHub publiée le 21 octobre à 12 h 06 UTC. Une enquête défensive aurait plusieurs points d’appui indépendants : recherche de secrets dans tout l’historique Git, inventaire des clés non révoquées, audit des appels à l’API interne, suivi des contournements de protection de branche, comparaison entre source qualifiée et source du build, puis inspection des roues et images publiées. Les journaux d’exécution avaient été partiellement effacés par l’attaquant ; les événements d’audit GitHub et les digests de registre gardent donc une valeur distincte.
La fenêtre confirmée est précise : sept roues PyPI publiées vers 11 h 40 UTC et isolées avant 13 h 23 ; images Docker publiées à partir de 11 h 46 et retirées ou réorientées avant 14 h 20. Les tags latest, main-latest et main-stable ont été concernés, pas uniquement v1.107.0. Les versions antérieures et le registre privé Enterprise étaient déclarés non affectés dans l’avis de l’éditeur.
Réponse d’un exploitant exposé
Vérifier les versions, les digests historiques et les journaux de déploiement, puis isoler les environnements qui ont démarré l’artefact. Un tag Docker corrigé aujourd’hui ne prouve pas que son digest était sain pendant la fenêtre d’attaque. LiteLLM recommande de reconstruire conteneurs et environnements Python depuis une source vérifiée ; si l’artefact a tourné avec un accès sortant, considérer les secrets accessibles comme exposés et les renouveler, y compris clés de fournisseurs de modèles, rôle IAM, DATABASE_URL et clés du proxy. Une simple désinstallation ne fait pas revenir un secret exfiltré. (Instructions officielles)
La cause systémique est l’addition de deux frontières mal tenues : un secret « supprimé » mais jamais invalidé, puis un pipeline qui autorisait un propriétaire compromis à changer la source du build. Les approbations et les signatures restaient présentes dans l’interface ; elles validaient un processus dont la provenance avait été détournée.
La revue des jetons et des droits de déploiement rejoint l’analyse de l’attaque Binance, avec une chaîne d’accès différente. Pour une plateforme d’agents, notre guide des contrats et de l’orchestration multi-agent explique comment borner les outils, les permissions et les actions soumises à validation ; ces contrôles complètent la vérification des dépendances.
Sources principales : rapport de cause racine LiteLLM, avis et mesures d’urgence LiteLLM.
#rootzero
Une question sur votre exposition ?
Écrivez-nous. Une personne de l’équipe technique vous répond, sources à l’appui.