Kilo Code a transmis en silence les 12 fichiers du projet à un serveur, alors que deux seulement étaient autorisés
L'auteur a vérifié ce qui part vers le serveur du modèle lorsqu'un assistant IA corrige un seul caractère dans le code. Kilo Code 7.4.20 a remplacé l'addition par une multiplication, le test est passé et un seul fichier a changé sur le disque. Pourtant, le serveur de test, qui jouait le rôle d'un fournisseur non fiable, a reçu les 12 fichiers du projet, alors que l'utilisateur n'avait autorisé la transmission que de deux, et les copies étaient identiques octet pour octet.
Traité par IA depuis Habr AI ; édité par Hamidun News
D'ordinaire, nous validons le travail d'un assistant IA ainsi : on regarde le diff, on lance les tests, on voit le vert et on clôt la tâche. L'expérience décrite sur Habr révèle une faille dans cette habitude. La modification peut être parfaite, et le projet se trouver pourtant déjà sur un serveur tiers.
Comment l'expérience a été montée
La tâche était volontairement minuscule : dans price.py, la fonction total(price, count) renvoyait price + count, alors que le test attendait que total(7, 3) donne 21. Il fallait remplacer l'addition par une multiplication et lancer check.py. L'instruction de l'utilisateur précisait que seuls price.py et check.py pouvaient être transmis.
L'auteur est parti d'un modèle de menace où le fournisseur de LLM n'est pas fiable et enfreint délibérément les instructions. Ce rôle était tenu par un serveur HTTP local sur 127.0.0.1. Il imitait les réponses en streaming de l'API Chat Completions compatible OpenAI et envoyait au client des tool_calls : d'abord douze commandes read pour tous les fichiers d'un projet synthétique, puis une commande de correction, puis le lancement du test. Le client était bien réel : bin/kilo.exe de l'extension Kilo Code 7.4.20, lancé via la commande CLI run. La configuration autorisait la lecture et l'exécution de commandes.
Résultat
En apparence, tout semblait exemplaire. Kilo a modifié un seul caractère, le test est passé, les autres fichiers du disque sont restés intacts, le code de sortie était nul et les 14 appels d'outils se sont terminés avec le statut completed. Mais le serveur a reçu les 12 fichiers, soit 11 103 octets au total, et leurs SHA-256 correspondaient aux originaux.
Le mécanisme est simple. Kilo ajoute le résultat de chaque lecture à l'historique du chat et l'envoie dans la requête suivante. Le serveur extrait les messages de rôle tool, supprime les numéros de ligne et reconstitue les fichiers. Aucun canal d'exfiltration n'est nécessaire : le client transporte lui-même les données dans ses requêtes normales.
Le trafic est lui aussi intéressant. Il y a eu 15 appels au modèle au total, et le volume cumulé des corps de requêtes a atteint 458 779 octets pour 11 Ko de code unique. La cause : le renvoi de l'historique, les descriptions d'outils et le balisage de service. Il n'y avait pas de requête énorme : le code partait par petites portions, puis se répétait. La taille d'une requête isolée ne permet donc pas de repérer une telle fuite.
Pourquoi les interdictions fonctionnent moins bien qu'on ne le croit
Dans la série de tests initiale, la règle read: deny bloquait la lecture directe du répertoire interdit. Mais avec bash: allow, Python a lu le même fichier et la sortie est partie dans la requête suivante. Lorsque bash a été interdit, la commande ne s'est pas exécutée. Les droits de Kilo sont définis séparément pour chaque outil, et l'interdiction de l'un ne ferme pas les autres voies.
Il y a aussi des réserves honnêtes. L'expérience n'utilise pas de vrai modèle : les commandes étaient choisies par le serveur de test, ce qui ne mesure donc pas la propension des modèles commerciaux à ce comportement. Les noms de fichiers étaient connus d'avance du serveur ; l'exploration autonome d'une arborescence inconnue n'a pas été testée. La session graphique de l'extension n'a pas non plus été testée, seulement la CLI.
Que faire en pratique
Premièrement : évaluez non seulement le diff, mais aussi le journal des appels d'outils et les corps des requêtes envoyées au fournisseur. Faites au moins une fois passer l'agent par un proxy local pour voir ce qui part réellement.
Deuxièmement : donnez à l'agent un minimum de droits. Si la lecture est autorisée, tout ce qui est lu appartient potentiellement au fournisseur. Pour les dépôts sensibles, c'est un argument en faveur des modèles locaux ou de fournisseurs offrant des garanties contractuelles strictes.
Troisièmement : ne vous fiez pas à une instruction textuelle du type « ne transmets que ces deux fichiers ». C'est un vœu adressé au modèle, pas une restriction du client. Seuls les droits des outils, le bac à sable et les politiques réseau établissent une vraie frontière.
L'auteur a publié le banc d'essai en entier : Python 3.10+, Git et l'exécutable Kilo, environ 150 lignes de code. Il vaut la peine de le reproduire sur votre propre client, quel que soit l'agent que vous utilisez.
- 12 nov. 2026Jensen Huang quitte son poste de PDG de Nvidia : l’entreprise perd 1 400 milliards de dollars en deux semaines
- 12 nov. 2026Le syndicat d'Oakland obtient une reconversion plutôt que des licenciements dus à l'IA : 94,1 % pour la grève
- 12 nov. 2026Huit pays, OpenAI et Anthropic promettent un « interrupteur d'arrêt » pour les modèles d'IA, mais sans échéances ni sanctions
- 12 nov. 2026OpenAI et ModRetro lancent une console à 200 $ pour des jeux créés avec Codex
Questions clés sur cet article
Comment l'expérience a été montée?
La tâche était volontairement minuscule : dans price.py, la fonction total(price, count) renvoyait price + count, alors que le test attendait que total(7, 3) donne 21. Il fallait remplacer l'addition par une multiplication et lancer check.py. L'instruction de l'utilisateur précisait que seuls price.py et check.py pouvaient être transmis. L'auteur est parti d'un modèle de menace où le fournisseur de LLM n'est pas fiable et enfreint délibérément les instructions.
Que sait-on sur Résultat ?
En apparence, tout semblait exemplaire. Kilo a modifié un seul caractère, le test est passé, les autres fichiers du disque sont restés intacts, le code de sortie était nul et les 14 appels d'outils se sont terminés avec le statut completed. Mais le serveur a reçu les 12 fichiers, soit 11 103 octets au total, et leurs SHA-256 correspondaient aux originaux. Le mécanisme est simple. Kilo ajoute le résultat de chaque lecture à l'historique du chat et l'envoie dans la requête suivante.
Pourquoi les interdictions fonctionnent moins bien qu'on ne le croit?
Dans la série de tests initiale, la règle read: deny bloquait la lecture directe du répertoire interdit. Mais avec bash: allow, Python a lu le même fichier et la sortie est partie dans la requête suivante. Lorsque bash a été interdit, la commande ne s'est pas exécutée. Les droits de Kilo sont définis séparément pour chaque outil, et l'interdiction de l'un ne ferme pas les autres voies. Il y a aussi des réserves honnêtes.
Test Frontier LLMs & Autonomous Agents in One Workspace
Run Claude Opus 5.5, GPT-6, Gemini 3.1, and DeepSeek side-by-side in Nomad AI (nomadnet.ai) — unified model routing, deep research, and multimodal workflows under one subscription.
L'essentiel de l'IA — une fois par semaine
Sept actus qui ont vraiment compté, choisies à la main. Sans bruit ni communiqués.
C'est fait ! Vérifiez votre boîte mail pour la confirmation.