← Tous les articles

La bombe fork nous a sauvés

Le malware présent dans LiteLLM 1.82.8 contenait un fichier .pth qui s’exécutait à chaque démarrage de Python. Il collectait les clés SSH, les identifiants cloud, les portefeuilles de cryptomonnaies et les secrets CI/CD, les chiffrait avec une clé RSA de 4096 bits, puis exfiltrait l’archive vers un domaine contrôlé par l’attaquant. La charge utile était bien conçue. Le chiffrement était solide. L’exfiltration était propre.1 Cet incident fait partie de ma série sur la sécurité des agents, consacrée aux défaillances réelles qui façonnent notre manière de construire la confiance dans les systèmes automatisés.

Le fichier .pth lançait également un processus Python enfant pour exécuter son travail. Ce processus enfant déclenchait à nouveau le fichier .pth. Ce qui créait un autre processus enfant. Qui le déclenchait encore. Une bombe fork exponentielle qui consommait 100 % du CPU et plus de 5 Go de RAM en quelques secondes.2

La bombe fork était un bug. L’attaquant ne souhaitait pas que le malware soit visible. Une implémentation correcte aurait fonctionné silencieusement à chaque invocation de Python sur chaque système infecté, potentiellement pendant des semaines. Au lieu de cela, les développeurs ont remarqué que leurs machines ralentissaient considérablement, ont investigué et ont découvert le voleur d’identifiants. PyPI a mis en quarantaine les deux versions 46 minutes après leur publication.1

Quarante-six mille installations en quarante-six minutes. Le mécanisme de détection était une erreur d’implémentation dans le malware.

TL;DR

  • Le bug : le voleur d’identifiants de LiteLLM 1.82.8 contenait un bug de bombe fork qui rendait les machines infectées extrêmement lentes. Sans ce bug, le voleur aurait fonctionné silencieusement pendant des semaines.
  • La faille : l’analyse statique, la surveillance comportementale et la revue de code ont toutes manqué l’attaque. Chaque couche de détection supposait qu’une autre couche l’intercepterait. Aucune ne l’a fait.3
  • La courbe : la qualité des attaquants s’améliore par itération. La technique .pth est désormais documentée publiquement. Le prochain attaquant en hérite sans le bug.
  • Ce qui fonctionne sans chance : la vérification de l’ancienneté des domaines en sortie, le profilage comportemental des installations de paquets, les fichiers canaris sur le système de fichiers, l’isolation des installations. Chacun fonctionne indépendamment de la qualité de la charge utile.
  • L’asymétrie : le défenseur choisit l’environnement. Si l’environnement d’installation ne contient aucun identifiant à voler, une charge utile parfaite ne récolte rien.

On a eu de la chance

Retirez la bombe fork de la charge utile et l’attaque réussit silencieusement. Le fichier .pth s’exécute avant tout import, avant tout code applicatif, avant tout bac à sable au niveau Python. Il n’y a aucun point d’accroche. Il n’y a aucune entrée de journal. Le voleur d’identifiants s’exécute, chiffre, exfiltre, et le processus Python continue normalement. Le développeur ne voit rien. Le pipeline CI ne voit rien. Le scanner de sécurité ne voit rien, car le scanner de sécurité était lui-même le vecteur d’attaque.3

L’histoire de la détection de LiteLLM 1.82.8 n’est pas « notre surveillance l’a détecté ». L’histoire est « l’attaquant a livré un bug ».

Ce n’est pas une base confortable pour la sécurité de la chaîne d’approvisionnement. Comme je le soutiens dans your agent sandbox is a suggestion, les frontières que nous supposons exister entre code de confiance et code non fiable sont bien plus perméables que la plupart des équipes ne le réalisent.

La courbe de qualité des attaquants

La qualité logicielle s’améliore par itération. C’est vrai pour les attaquants comme pour les défenseurs. La campagne de TeamPCP a touché cinq écosystèmes en une semaine : GitHub Actions, Docker Hub, npm, Open VSX et PyPI.4 Chaque compromission d’écosystème utilisait des identifiants récoltés lors de la précédente. La campagne a démontré une sophistication opérationnelle : enregistrement de domaine 24 heures avant la livraison de la charge utile, détournement de tags sur des références mutables, et contournement de la rotation des identifiants via des changements de clés Aqua Security incomplets.

La bombe fork était la seule erreur dans une opération par ailleurs compétente. La prochaine campagne ne commettra pas cette erreur. La technique du fichier .pth est désormais documentée publiquement, analysée par CrowdStrike, Microsoft, Wiz et Palo Alto.3 Le prochain attaquant hérite de la technique sans le bug.

La capacité adversariale suit la même courbe d’amélioration que la capacité défensive. La technique est publique. L’analyse est publique. Le prochain attaquant commence là où TeamPCP a terminé. J’explore ce que cette courbe signifie pour les systèmes autonomes dans what actually breaks unsupervised.

La détection ne peut pas dépendre des erreurs de l’attaquant

Le modèle actuel de détection de la chaîne d’approvisionnement comporte trois couches, et les trois ont échoué pour LiteLLM :

L’analyse statique l’a manqué. Le fichier .pth est une fonctionnalité légitime de Python. La charge utile était doublement encodée en base64 et décodée à l’exécution. Les scanners statiques qui recherchent des motifs malveillants connus ne trouvent rien parce que le motif est nouveau.

La surveillance comportementale l’a manqué. Le voleur d’identifiants effectuait une seule requête HTTPS POST sortante vers un domaine qui ressemblait à un service légitime (models.litellm.cloud). La surveillance du trafic sortant inspectant les domaines de destination aurait eu besoin de savoir que ce domaine spécifique avait été enregistré 24 heures plus tôt. La plupart des moniteurs de trafic sortant ne vérifient pas l’ancienneté des domaines.

La revue de code l’a manqué. Les versions malveillantes ont été publiées directement sur PyPI, contournant entièrement le pipeline CI/CD de GitHub. Il n’y avait aucune pull request à examiner. Il n’y avait aucun diff à inspecter. L’attaquant a utilisé des identifiants de publication volés pour téléverser des paquets pré-compilés.

Chaque couche de détection supposait qu’une partie différente de la chaîne d’attaque intercepterait le problème. Aucune ne l’a fait. La bombe fork a intercepté le problème.

Ce qui détecte réellement un malware silencieux

Si vous ne pouvez pas compter sur les erreurs de l’attaquant, il vous faut des mécanismes de détection qui fonctionnent indépendamment de la qualité de l’implémentation.

Vérification de l’ancienneté des domaines sur les requêtes sortantes. Le domaine d’exfiltration avait été enregistré 24 heures avant l’attaque. Une règle de pare-feu signalant les requêtes sortantes vers des domaines de moins de 7 jours d’ancienneté l’aurait détecté. La règle est simple, le taux de faux positifs est gérable, et elle détecte le schéma d’exfiltration le plus courant.

Profilage comportemental des processus Python. Un pip install qui effectue soudainement des requêtes HTTPS POST vers un domaine inconnu est anormal. Une surveillance comportementale au niveau des processus, suivant l’activité réseau pendant l’installation de paquets, signalerait cela.

Fichiers canaris sur le système de fichiers. Placez une fausse clé SSH à un chemin canari et un faux identifiant AWS à un autre chemin canari. Surveillez tout processus qui lit ces fichiers. Un voleur d’identifiants balayant les chemins standards lira les canaris. Un processus légitime ne le fera pas. Le canari déclenche une alerte avant que l’exfiltration ne se termine.

Isolation des installations. Exécutez pip install dans un environnement sans accès aux véritables identifiants. Copiez les paquets installés dans l’environnement de production ensuite. Le fichier .pth se déclenche pendant le propre processus Python de pip, ce qui signifie que le voleur d’identifiants s’exécute pendant l’installation. Si l’environnement d’installation ne contient aucun identifiant à voler, l’attaque ne récolte rien.

Aucun de ces mécanismes ne nécessite que l’attaquant commette une erreur. Ils fonctionnent indépendamment de la qualité de la charge utile. Le schéma architectural — concevoir des environnements où même une attaque parfaite ne récolte rien — repose sur le même principe que deploy and defend: the agent trust paradox.

L’asymétrie

La défense possède un avantage structurel : le défenseur choisit l’environnement. L’attaquant doit opérer dans l’environnement où le paquet est installé, quel qu’il soit. Si cet environnement ne contient aucun identifiant, aucun accès réseau, et des fichiers canaris sur le système de fichiers, la charge utile réussit techniquement mais échoue opérationnellement.

L’attaque LiteLLM a fonctionné parce que l’environnement d’installation était le même environnement qui contenait les identifiants de publication, les clés SSH et les jetons cloud. La bombe fork n’avait aucune pertinence pour l’architecture de sécurité. Elle était pertinente pour la chronologie.

La prochaine fois, la bombe fork ne sera pas là. Les identifiants seront toujours dans le même environnement que le gestionnaire de paquets. La question est de savoir si vous aurez modifié l’environnement avant que le prochain attaquant ne livre une charge utile propre. Mon analyse de l’architecture d’agent Ralph montre comment structurer les systèmes d’agents pour qu’un composant compromis ne puisse pas escalader au-delà de sa frontière d’isolation.


FAQ

Pourquoi l’attaquant n’a-t-il pas testé la bombe fork ?

Le fichier .pth lançant un processus enfant est un choix d’implémentation raisonnable pour exécuter une charge utile sans bloquer le processus parent. Le déclenchement récursif est une interaction subtile entre .pth et l’initialisation de site.py par Python. C’est le type de bug qui apparaît en tests d’intégration mais pas en tests unitaires, et les auteurs de malware ont peu d’occasions de réaliser des tests d’intégration dans des environnements réalistes.

La bombe fork aurait-elle pu être intentionnelle ?

Peu probable. La bombe fork a rendu le malware immédiatement visible, ce qui est l’opposé de l’objectif de l’attaquant. Un voleur d’identifiants silencieux fonctionnant pendant des semaines récolte des ordres de grandeur plus d’identifiants qu’un malware détecté en 46 minutes.

La vérification de l’ancienneté des domaines est-elle praticable à grande échelle ?

Oui. L’ancienneté d’un domaine est disponible via WHOIS ou la date d’enregistrement DNS via des APIs. La vérification ajoute quelques millisecondes de latence par requête. La plupart des organisations peuvent mettre en liste blanche les nouveaux domaines connus.


Sources


  1. FutureSearch (Daniel Hnyk), “LiteLLM Hack: Were You One of the 47,000?” Mars 2026. 

  2. isfinne et al., “LiteLLM Supply Chain Attack,” GitHub Issue #24512, mars 2026. 

  3. Blake Crosley, “The Supply Chain Is the Attack Surface,” blakecrosley.com, mars 2026. 

  4. Kaspersky, “Trojanization of Trivy, Checkmarx, and LiteLLM Solutions,” Mars 2026. 

  5. Blake Crosley, “When Your Agent Becomes the Researcher,” blakecrosley.com, mars 2026. 

Articles connexes

Votre agent a un intermédiaire que vous n'avez pas vérifié

Des chercheurs ont testé 28 routeurs LLM API. 17 ont touché aux identifiants canari AWS. Un a vidé de l'ETH d'une clé pr…

14 min de lecture

Attaques de la chaîne d'approvisionnement IA : la chaîne d'approvisionnement est la surface

Trivy a été compromis par détournement de tags, puis LiteLLM sur PyPI, puis 47 000 installations en 46 minutes. La chaîn…

16 min de lecture

La boucle Ralph : comment je fais tourner des agents IA autonomes pendant la nuit

J'ai construit un système d'agents autonomes avec des hooks d'arrêt, des budgets de spawn et une mémoire par système de …

10 min de lecture