← Tous les articles

La fork bomb nous a sauvés

Le malware présent dans LiteLLM 1.82.8 contenait un fichier .pth qui s’exécutait au démarrage de n’importe quel processus 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 s’inscrit dans ma série sécurité des agents, consacrée aux défaillances réelles qui façonnent notre manière de bâtir la confiance dans les systèmes automatisés.5

Le fichier .pth engendrait par ailleurs un processus Python enfant pour accomplir sa besogne. Ce processus enfant déclenchait à nouveau le fichier .pth. Lequel engendrait un autre processus enfant. Lequel le déclenchait encore. Une fork bomb exponentielle qui consommait 100 % du CPU et plus de 5 Go de RAM en quelques secondes.2

Cette fork bomb était un bug. L’attaquant n’avait pas prévu que son malware soit visible. Une version correctement implémentée aurait tourné silencieusement à chaque invocation de Python sur chaque système infecté, potentiellement pendant des semaines. Résultat : les développeurs ont vu leurs machines s’effondrer, ont enquêté et ont découvert le voleur d’identifiants. PyPI a mis les deux versions en quarantaine 46 minutes après leur publication.1

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

Lorsqu’une dépendance d’un agent IA installe un paquet contenant une fork bomb, la création exponentielle de processus consomme 100 % du CPU et plusieurs gigaoctets de RAM en quelques secondes, rendant la machine inutilisable. Dans l’incident LiteLLM 1.82.8, cette fork bomb accidentelle est la seule raison pour laquelle une charge utile voleuse d’identifiants a été détectée : les développeurs ont constaté que leurs machines s’enlisaient et ont enquêté. Sans ce bug, le malware aurait exfiltré silencieusement clés SSH, identifiants cloud et portefeuilles crypto pendant des semaines avant d’être découvert.

L’essentiel

  • Le bug : le voleur d’identifiants de LiteLLM 1.82.8 comportait une fork bomb qui mettait les machines infectées à genoux. Sans ce bug, il aurait tourné en silence pendant des semaines.
  • L’angle mort : analyse statique, surveillance comportementale et relecture de code ont toutes laissé passer l’attaque. Chaque couche de détection supposait qu’une autre couche intercepterait la menace. Aucune ne l’a fait.3
  • La courbe : la qualité des attaquants progresse à chaque itération. La technique du .pth est désormais publiquement documentée. Le prochain attaquant en héritera sans le bug.
  • Ce qui fonctionne sans coup de chance : vérification de l’âge des domaines sur le trafic sortant, référence comportementale pour les installations de paquets, leurres sur le système de fichiers, isolation de l’installation. Chacun de ces mécanismes tient, quelle que soit la qualité de la charge utile.
  • L’asymétrie : c’est le défenseur qui choisit l’environnement. Si l’environnement d’installation ne contient aucun identifiant à voler, une charge utile parfaite ne récolte rien.

Nous avons eu de la chance

Retirez la fork bomb de la charge utile et l’attaque réussit en silence. Le fichier .pth s’exécute avant tout import, avant tout code applicatif, avant tout sandbox de niveau Python. Il n’existe aucun point d’accroche. Aucune entrée de journal. Le voleur d’identifiants s’exécute, chiffre, exfiltre, et le processus Python poursuit normalement son cours. Le développeur ne voit rien. Le pipeline CI ne voit rien. L’outil d’analyse de sécurité ne voit rien, puisque c’est précisément lui qui a servi de vecteur d’attaque.3

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

Voilà un fondement bien inconfortable pour la sécurité de la chaîne d’approvisionnement. Comme je le défends dans le sandbox de votre agent n’est qu’une suggestion, les frontières que nous supposons exister entre code de confiance et code non fiable sont bien plus poreuses que la plupart des équipes ne l’imaginent.

La courbe de qualité des attaquants

La qualité logicielle progresse à chaque itération. Cela vaut pour les attaquants autant que pour les défenseurs. La campagne de TeamPCP a frappé cinq écosystèmes en une seule semaine : GitHub Actions, Docker Hub, npm, Open VSX et PyPI.4 Chaque compromission d’écosystème s’appuyait sur des identifiants récoltés lors de la précédente. La campagne a fait preuve d’une réelle sophistication opérationnelle : enregistrement du 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 d’identifiants grâce à un changement de clés incomplet chez Aqua Security.

La fork bomb constituait l’unique faux pas d’une opération par ailleurs maîtrisée. La prochaine campagne ne commettra pas cette erreur. La technique du fichier .pth est désormais publiquement documentée, analysée par CrowdStrike, Microsoft, Wiz et Palo Alto.3 Le prochain attaquant hérite de la technique, sans le bug.

La capacité offensive suit la même courbe de progression que la capacité défensive. La technique est publique. L’analyse est publique. Le prochain attaquant démarre là où TeamPCP s’est arrêté. J’explore ce que cette courbe implique pour les systèmes autonomes dans ce qui casse vraiment sans supervision.

La détection ne peut pas reposer sur les erreurs de l’attaquant

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

L’analyse statique est passée à côté. Le fichier .pth est une fonctionnalité Python légitime. La charge utile était encodée deux fois en base64 et décodée à l’exécution. Les analyseurs statiques qui traquent des motifs malveillants connus ne trouvent rien, puisque le motif est inédit.

La surveillance comportementale est passée à côté. Le voleur d’identifiants effectuait une seule requête HTTPS POST sortante vers un domaine qui ressemblait à un service légitime (models.litellm.cloud). Une surveillance du trafic sortant qui inspecte les domaines de destination aurait besoin de savoir que ce domaine précis avait été enregistré 24 heures auparavant. Or la plupart des dispositifs de surveillance du trafic sortant ne vérifient pas l’âge des domaines.

La relecture de code est passée à côté. Les versions malveillantes ont été publiées directement sur PyPI, contournant entièrement le pipeline CI/CD GitHub. Il n’y avait aucune pull request à relire. Aucun diff à inspecter. L’attaquant a utilisé des identifiants de publication volés pour téléverser des paquets déjà construits.

Chaque couche de détection supposait qu’une autre partie de la chaîne d’attaque intercepterait le problème. Aucune ne l’a fait. C’est la fork bomb qui l’a intercepté.

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 quelle que soit la qualité de l’implémentation.

Vérifier l’âge 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 aurait permis de détecter cette attaque. La règle est simple, le taux de faux positifs reste gérable, et elle couvre le schéma d’exfiltration le plus courant.

Établir une référence comportementale pour les processus Python. Un pip install qui se met soudain à émettre 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 des paquets, le signalerait.

Des leurres sur le système de fichiers. Placez une fausse clé SSH à un emplacement piégé et un faux identifiant AWS à un autre. Surveillez tout processus qui lit ces fichiers. Un voleur d’identifiants qui ratisse les chemins standards lira les leurres. Un processus légitime, non. Le leurre déclenche une alerte avant que l’exfiltration ne s’achève.

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

Aucun de ces mécanismes n’exige que l’attaquant commette une erreur. Ils fonctionnent quelle que soit la qualité de la charge utile. Ce modèle architectural — concevoir des environnements où même une attaque parfaite ne récolte rien — obéit au même principe que déployer et défendre : le paradoxe de la confiance envers les agents.

L’asymétrie

La défense dispose d’un avantage structurel : c’est le défenseur qui choisit l’environnement. L’attaquant, lui, doit composer avec l’environnement dans lequel le paquet est installé, quel qu’il soit. Si cet environnement ne contient aucun identifiant, n’a aucun accès réseau et comporte des leurres sur le système de fichiers, la charge utile réussit techniquement mais échoue opérationnellement.

L’attaque contre LiteLLM a fonctionné parce que l’environnement d’installation était aussi celui qui hébergeait les identifiants de publication, les clés SSH et les jetons cloud. La fork bomb n’avait aucune incidence sur l’architecture de sécurité. Elle en a eu une sur le calendrier.

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


FAQ

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

Qu’un fichier .pth engendre 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 résulte d’une interaction subtile entre .pth et l’initialisation de site.py dans Python. C’est le genre de bug qui apparaît lors des tests d’intégration, mais pas des tests unitaires — et les auteurs de malwares ont peu d’occasions de mener des tests d’intégration en conditions réalistes.

La fork bomb aurait-elle pu être intentionnelle ?

C’est peu probable. Elle rendait le malware immédiatement visible, à rebours exact de l’objectif de l’attaquant. Un voleur d’identifiants silencieux qui tourne pendant des semaines récolte plusieurs ordres de grandeur d’identifiants de plus qu’un voleur repéré en 46 minutes.

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

Oui. L’âge d’un domaine s’obtient via WHOIS ou via des API renvoyant la date d’enregistrement DNS. La vérification ajoute quelques millisecondes de latence par requête. La plupart des organisations peuvent placer sur liste blanche les nouveaux domaines qu’elles connaissent.


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é

Sur 28 routeurs LLM API testés, 17 ont touché aux identifiants canari AWS. La couche routeur est une surface d'attaque.

14 min de lecture

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

Trivy compromis par détournement de tags, LiteLLM sur PyPI, 47 000 installations en 46 minutes : la chaîne d'approvision…

16 min de lecture

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

J'ai bâti un système d'agents autonomes avec hooks d'arrêt, budgets de spawn et mémoire sur fichiers : les échecs et ce …

10 min de lecture