Présentation de la compromission

Le 21 octobre 2026, la version 1.107.0 du package litellm publiée sur PyPI a été retirée après la découverte d’un implant malveillant. Les sept roues (Linux, macOS, Windows) installent trois fichiers supplémentaires dans site‑packages. Deux de ces fichiers s’exécutent à chaque démarrage d’un processus Python, même si le module litellm n’est jamais importé. Le dépôt GitHub officiel ne contient aucune de ces ressources, ce qui indique une injection en chaîne d’approvisionnement.

Mécanisme d’injection dans la distribution

Le fichier pyproject.toml de la source sdist comporte une ligne supplémentaire dans la section [tool.maturin] :

data = "cook"
Cette directive copie le répertoire cook/ dans le répertoire litellm-1.107.0.data/purelib/ du wheel. Le répertoire cook/ est absent du sdist, ce qui rend la modification invisible dans le code source. Le RECORD du wheel répertorie les trois fichiers ajoutés : cook.pth (12 octets), cook.py (22 252 octets) et sitecustomize.py (25 509 octets).

Fonctionnement du vol de crédentials et du backdoor

Le fichier cook.pth contient simplement

import cook
, ce qui déclenche l’exécution de cook.py à chaque lancement de l’interpréteur. cook.py encapsule environ 61 KB de code Python compressé et encodé en base64, exécuté via exec(zlib.decompress(...)). Le script collecte plus d’une vingtaine de catégories de secrets : clés SSH, identifiants cloud, tokens CI/CD, mots de passe de navigateurs, clés LLM, etc. Les données sont sérialisées en JSON, chiffrées avec une clé AES‑256‑CBC aléatoire, puis la clé symétrique est encryptée avec RSA‑OAEP à l’aide d’une clé publique RSA‑4096 intégrée. Le paquet résultant (tar.gz contenant hdr.json, data.bin, key.bin) est envoyé par POST vers http://www.litellm.dev/healthcheck avec l’en‑tête X-Token: XWiA8gZNa7NcX2XRoAEb. Après un envoi réussi, le script crée le fichier /tmp/.pc_once_72129118c59f5636c0bb pour limiter l’opération à une fois par hôte.

Parallèlement, sitecustomize.py est importé automatiquement par Python. Il crée un daemon qui, chaque heure, lit domain.txt depuis le dépôt GitHub letters9813/pythonclient-test, télécharge le fichier codepy depuis le domaine indiqué, puis l’exécute via exec(). Le daemon utilise un verrou exclusif (/tmp/remote_code_loader.lock) et se détache du processus parent (fork, setsid, redirection vers /dev/null). Le serveur de commande a disparu deux heures après la publication, mais les hôtes déjà infectés auraient pu recevoir du code supplémentaire.

Impact, indicateurs et mesures de remédiation

Les images Docker v1.107.0, latest, main‑latest et main‑stable hébergées sur Docker Hub et GHCR ont également transporté le code malveillant entre 11:46 UTC et 14:20 UTC. Les versions 1.106.2, 1.107.0rc1 et 1.107.0rc2 restent propres, tout comme les paquets auxiliaires litellm-proxy-extras==0.4.110 et litellm-enterprise==0.1.78. LiteLLM a révoqué les jetons GitHub CLI de trois développeurs, suspectés d’avoir été compromis via les logs d’une instance interne exposée. La chaîne d’approvisionnement a été détournée en contournant la protection de branche grâce à un token d’organisation, puis en redirigeant le workflow de publication vers un dépôt factice. Les équipes de sécurité doivent vérifier les empreintes SHA‑256 des wheels, rechercher les fichiers cook.pth, cook.py et sitecustomize.py dans leurs environnements, et révoquer tout token exposé. La suppression du package sur PyPI à 13:23 UTC constitue la première étape de containment.