← Tous les articles

Votre agent a deux entrées non fiables

Tiré du guide: Claude Code Comprehensive Guide

Un programme traditionnel a une seule frontière de confiance : l’entrée qu’un utilisateur lui remet. Vous validez à cette lisière et vous avez pratiquement fini. Un agent en a discrètement ajouté deux autres, et la plupart des outils construits autour des agents ne traitent que l’une d’elles comme réelle.

La première nouvelle entrée est le code que le modèle écrit et que votre processus exécute. La seconde est la sortie d’outil que le modèle lit et sur laquelle il agit ensuite. Toutes deux pénètrent dans votre système depuis un endroit que vous ne contrôlez pas – la distribution d’échantillonnage d’un modèle de langage, ou le serveur d’un tiers – et toutes deux sont traitées comme fiables dès leur arrivée. Si la sécurité des agents semble si instable en ce moment, c’est que l’industrie a une réponse crédible pour la première entrée et continue de faire comme si la seconde était le même problème. Ce n’est pas le cas.

L’essentiel

  • Les agents ont deux entrées non fiables, pas une. Le code généré par le modèle que votre environnement d’exécution exécute, et la sortie d’outil ou de serveur que votre modèle ingère et sur laquelle il agit. Elles échouent de manières différentes et exigent des défenses différentes – les confondre, c’est ce qui fait qu’on se sent en bac à sable tout en restant exploitable.12
  • L’exécution de code non fiable a enfin une réponse d’isolation crédible. Le micropython-wasm de Simon Willison exécute du Python écrit par le modèle dans un bac à sable WebAssembly avec des limites de mémoire et de CPU et un accès contrôlé aux fichiers et au réseau – les caractéristiques dont un vrai bac à sable a besoin, sur un substrat « éprouvé dans les navigateurs depuis près d’une décennie ».1
  • L’empoisonnement d’outils n’est pas un problème d’exécution de code, donc un bac à sable de code n’y fait rien. Les instructions malveillantes cachées dans la description d’un outil MCP sont « invisibles pour les utilisateurs mais visibles pour les modèles d’IA », et elles peuvent détourner un agent même si l’outil empoisonné n’est jamais exécuté.23
  • Le problème le plus profond est un écart de confiance entre le moment de la connexion et l’exécution. Les descriptions d’outils sont examinées une fois, à l’approbation ; les réponses d’outils passent directement dans le contexte du modèle sans vérification équivalente – et un serveur malveillant peut changer la description après que vous l’avez approuvée.2

Deux entrées, deux modes de défaillance

Tenez les deux entrées côte à côte, parce que l’asymétrie est tout le propos.

Quand un modèle écrit du code et que vous l’exécutez avec exec(), le mode de défaillance est le code fait quelque chose à votre machine – il lit un fichier qu’il ne devrait pas, ouvre un socket, fait tourner le CPU indéfiniment, corrompt l’état. Le rayon d’explosion, c’est votre processus et tout ce qu’il peut atteindre. La défense est ancienne et bien comprise : l’isolation. Exécutez le code quelque part où il ne peut pas toucher ce qui compte.

Quand un modèle lit une sortie d’outil et agit dessus, le mode de défaillance est les mots changent ce que le modèle décide de faire. Rien ne s’exécute sur votre hôte au sens classique ; à la place, un texte arrivé comme « donnée » est interprété comme « instruction », et l’agent – qui détient vos identifiants – l’exécute. Le rayon d’explosion, c’est tout ce que votre agent est autorisé à faire. Aucune isolation de processus n’y change rien, parce que l’agent était censé pouvoir lire cet outil et agir dessus. L’exploit emprunte le chemin légitime.

Un bac à sable de code est un mur autour de la première entrée. Il est nécessaire, et il devient enfin bon. Il est aussi totalement muet sur la seconde.

L’entrée qui a enfin un bac à sable

Le 6 juin 2026, Simon Willison a publié micropython-wasm, un paquet alpha pour exécuter du Python dans un bac à sable WebAssembly, après des années d’approches qui ne convenaient jamais tout à fait.1 La motivation est exactement la première entrée non fiable : il veut exécuter du code généré par un LLM dans son Datasette Agent sans mettre l’hôte en danger, et comme il le dit, « un plugin bogué ou malveillant pourrait tout casser ou faire fuiter des données privées ».1

Ce qui mérite l’attention, c’est la liste de contrôle qu’il satisfait réellement, parce que cette liste est la définition d’un bac à sable utilisable :

  • Des limites de mémoire et de CPU, pour qu’un while True: s += "x" écrit par le modèle ne puisse pas épuiser l’hôte. Le CPU est borné par le mécanisme de « fuel » de wasmtime – à propos duquel Willison est honnête, notant que les unités sont « difficiles à raisonner ».1
  • Un accès contrôlé aux fichiers et au réseau, refusé par défaut plutôt qu’ouvert par défaut.
  • Un modèle d’isolation propre : le code s’exécute sur un thread séparé derrière une file requête/réponse, l’interpréteur WASM bloquant sur une fonction hôte jusqu’à ce qu’on lui confie du travail – de sorte que le code non fiable ne partage jamais l’espace d’adressage de l’hôte.1
  • Un substrat avec un historique. Il a choisi WebAssembly parce qu’il a été « conçu dès le départ pour prendre en charge toutes les caractéristiques qui m’importent et éprouvé dans les navigateurs depuis près d’une décennie », et MicroPython parce que Pyodide, orienté navigateur, n’est pas pris en charge côté serveur.1

L’honnêteté est la marque du bon travail de sécurité. Willison le livre en alpha et écrit qu’il n’est « pas prêt à le recommander à quiconque n’est pas disposé à prendre un risque important ».1 C’est la posture de la porte de l’évidence – affirmer exactement ce que vous avez vérifié et rien de plus. Le point n’est pas que ce paquet-là soit la réponse ; c’est que la forme de la réponse pour le code non fiable est désormais claire et reproductible : une vraie frontière d’isolation avec des limites de ressources et des E/S refusées par défaut. La première entrée devient un problème d’ingénierie résolu.

Le piège, c’est de croire que le résoudre vous met en sécurité.

L’entrée qui n’en a pas

La seconde entrée n’exécute pas de code, donc le mur ne fait rien. Le 1er avril 2025, Invariant Labs a divulgué l’attaque par empoisonnement d’outils : « des instructions malveillantes sont intégrées dans les descriptions d’outils MCP, invisibles pour les utilisateurs mais visibles pour les modèles d’IA ».2 L’asymétrie est l’exploit – « les modèles d’IA voient les descriptions d’outils complètes, y compris les instructions cachées, tandis que les utilisateurs ne voient généralement que des versions simplifiées dans leur interface ».2 Un outil qui affiche, dans l’interface, « additionne deux nombres » peut porter, dans la description que le modèle consomme réellement, une instruction de lire ~/.ssh/id_rsa et de l’exfiltrer via un paramètre caché.2 L’OWASP catalogue désormais cela comme une classe d’attaque nommée.3

Deux propriétés la rendent redoutable d’une manière que l’isolation ne peut pas atteindre :

Elle se déclenche sans que l’outil soit appelé. Les instructions empoisonnées vivent dans la description, que le modèle ingère quand il considère l’ensemble d’outils – l’attaque peut donc aboutir même si la fonction ne s’exécute jamais.3 Il n’y a aucun événement de code à mettre en bac à sable.

La confiance est accordée une fois et abusée plus tard. Les descriptions d’outils sont examinées au moment de la connexion, quand vous approuvez un serveur. Les réponses passent ensuite directement dans le contexte du modèle à l’exécution sans vérification équivalente – et, dans la découverte du « rug pull » d’Invariant, « un serveur malveillant peut modifier la description de l’outil après que le client l’a déjà approuvée ».2 Votre approbation unique ne sécurise rien de continu.

La démonstration canonique n’est pas hypothétique. Des chercheurs ont empoisonné une issue GitHub avec du texte injecté ; quand un développeur a demandé à son assistant de passer en revue les issues ouvertes, l’agent a ingéré l’issue, suivi les instructions cachées, utilisé le jeton du développeur pour lire des dépôts privés, et fait fuiter leur contenu dans une pull request publique.3 Chaque action individuelle était autorisée. L’agent a fait exactement ce à quoi sert un agent. C’est pourquoi un bac à sable de code est hors sujet ici – rien de non fiable n’a été exécuté ; du texte non fiable a simplement été promu au rang d’instruction dans un processus qui détient de vrais identifiants. C’est la même leçon que Ken Thompson a laissée dans Reflections on Trusting Trust : le danger n’est pas le code que vous inspectez, c’est la confiance que vous accordez sans inspecter.

Défendre la seconde entrée

Si l’isolation est la défense pour le code, la défense pour la sortie d’outil consiste à traiter la frontière entre donnée et instruction comme réelle, à l’exécution, à chaque fois – ce que le modèle d’approbation à la connexion saute. Les propres recommandations MCP de Microsoft atterrissent au même endroit, préconisant des « prompt shields » qui détectent et filtrent les instructions injectées, plus le spotlighting, où « l’inclusion de délimiteurs dans le message système délimite explicitement l’emplacement du texte d’entrée » pour que le modèle distingue le contenu de la commande.4 Concrètement :

  • Revérifier les descriptions à l’exécution, pas seulement à l’approbation. Épinglez la définition d’outil que vous avez approuvée et détectez quand la description d’un serveur change sous vos pieds. Le rug pull ne fonctionne que parce que personne ne regarde deux fois.2
  • Marquer explicitement la frontière donnée/instruction. Les réponses d’outils sont des données, pas des directives – et la version pratique est le spotlighting : délimiter la sortie d’outil dans le contexte pour que le modèle sache, structurellement, qu’il s’agit de contenu sur lequel raisonner et non de commandes à suivre.4 Cela se combine avec l’autorisation au niveau des actions sur les outils MCP pour que même un agent détourné ne puisse pas atteindre les appels à fortes conséquences.
  • Appliquer le moindre privilège au chemin autorisé. L’exploit GitHub a fonctionné parce qu’un seul agent détenait à la fois « lire les dépôts privés » et « ouvrir une PR publique » – et le moindre privilège est exactement ce que Microsoft nomme comme hygiène fondamentale contre ces attaques.4 La sécurité par compartimentation de Joanna Rutkowska est le même instinct au niveau de l’architecture : supposer qu’un domaine est compromis et s’assurer qu’il ne peut pas atteindre les autres. Un agent qui lit des issues ne devrait pas être l’agent qui détient le chemin d’exfiltration.
  • Surveiller les sorties, parce que l’exfiltration est le gain. La plupart de ces attaques se terminent à la même étape – les données qui partent. Une vision de type sortie silencieuse attrape la conséquence même quand l’injection a franchi la porte d’entrée.

Rien de tout cela n’est un mur. Ce sont des portes sur un chemin que l’agent est censé emprunter – le genre de sécurité plus difficile, moins satisfaisant, et le genre que la seconde entrée exige réellement.

Ce que j’en retiens

Le modèle mental que je garde, c’est que « mon agent est-il en bac à sable ? » est la mauvaise question, parce qu’elle suppose silencieusement qu’il n’y a qu’une frontière à défendre. Il y en a deux. Le code que mon modèle écrit a besoin d’un mur – et grâce à des travaux comme ceux de Willison, construire ce mur devient une tâche d’ingénierie normale avec une spécification claire. La sortie d’outil que mon modèle lit a besoin de tout autre chose : un environnement d’exécution qui ne laisse jamais une donnée devenir discrètement une instruction, et un modèle d’autorisation si serré qu’un agent détourné ne peut quand même pas faire grand-chose. Les confondre, c’est comme cela qu’on finit par se sentir protégé – « regardez, le code tourne en WASM » – tout en restant grand ouvert par l’entrée sur laquelle personne n’a posé de porte.

La continuité plus profonde, c’est que les agents n’ont pas tant inventé une nouvelle catégorie de vulnérabilité qu’ajouté de nouveaux endroits où une ancienne peut vivre. L’entrée non fiable a toujours été la racine de la sécurité ; l’ère des agents lui a simplement donné deux nouvelles portes – une que vous pouvez verrouiller par l’isolation, une que vous ne pouvez que surveiller avec discipline. Construisez le mur et la porte. Un mur seul, sur un système à deux entrées, est une demi-défense qui a l’air d’une défense entière.

Questions fréquentes

Quelles sont les deux entrées non fiables d’un agent IA ?

Le code généré par le modèle que votre environnement d’exécution exécute, et la sortie d’outil ou de serveur que votre modèle lit et sur laquelle il agit ensuite. La première peut endommager l’hôte directement ; la seconde peut détourner les décisions de l’agent en utilisant les identifiants et permissions que l’agent détient déjà. Elles exigent des défenses différentes – l’isolation pour le code, la séparation donnée/instruction à l’exécution et une autorisation stricte pour la sortie d’outil.12

Un bac à sable de code protège-t-il contre l’empoisonnement d’outils MCP ?

Non. L’empoisonnement d’outils n’exécute pas de code sur votre hôte – il intègre dans la description d’un outil des instructions que le modèle traite comme fiables, et il peut se déclencher même si l’outil n’est jamais appelé.23 Un bac à sable isole l’exécution, il ne fait donc rien contre une attaque qui emprunte les actions légitimes et autorisées de l’agent.

Qu’est-ce qu’une attaque par empoisonnement d’outils ?

Divulguée par Invariant Labs en avril 2025, c’est une attaque où « des instructions malveillantes sont intégrées dans les descriptions d’outils MCP, invisibles pour les utilisateurs mais visibles pour les modèles d’IA ».2 Parce que le modèle voit la description complète tandis que l’utilisateur voit une étiquette d’interface simplifiée, des instructions cachées – par exemple lire des clés SSH et les exfiltrer – peuvent détourner l’agent. L’OWASP la suit désormais comme une classe d’attaque nommée.23

Qu’est-ce que l’écart de confiance entre connexion et exécution ?

Les descriptions d’outils sont examinées une fois, quand vous approuvez un serveur (à la connexion). Les réponses d’outils passent ensuite dans le contexte du modèle à l’exécution sans vérification équivalente, et un serveur malveillant peut changer une description après l’approbation (un « rug pull »).2 Le correctif consiste à vérifier à l’exécution, pas seulement à l’approbation.


Sources


  1. Simon Willison, « Running Python code in a sandbox with MicroPython and WASM, » simonwillison.net, 6 juin 2026. Présente le paquet alpha micropython-wasm et le plugin datasette-agent-micropython ; la motivation selon laquelle « un plugin bogué ou malveillant pourrait tout casser ou faire fuiter des données privées » ; la liste de contrôle du bac à sable (limites mémoire/CPU via le « fuel » de wasmtime, accès contrôlé aux fichiers/au réseau, isolation requête/réponse sur thread séparé) ; la justification selon laquelle WebAssembly a été « conçu dès le départ pour prendre en charge toutes les caractéristiques qui m’importent et éprouvé dans les navigateurs depuis près d’une décennie » ; et la mise en garde qu’il n’est « pas prêt à le recommander à quiconque n’est pas disposé à prendre un risque important ». ↩↩↩↩↩↩↩↩↩

  2. Luca Beurer-Kellner et Marc Fischer, « MCP Security Notification : Tool Poisoning Attacks, » Invariant Labs, 1er avril 2025. Divulgation originale : « Une attaque par empoisonnement d’outils se produit lorsque des instructions malveillantes sont intégrées dans les descriptions d’outils MCP, invisibles pour les utilisateurs mais visibles pour les modèles d’IA » ; l’écart de visibilité (« les modèles d’IA voient les descriptions d’outils complètes, y compris les instructions cachées, tandis que les utilisateurs ne voient généralement que des versions simplifiées dans leur interface ») ; la découverte du « rug pull » selon laquelle « un serveur malveillant peut modifier la description de l’outil après que le client l’a déjà approuvée » ; et l’exemple du add empoisonné lisant ~/.cursor/mcp.json et ~/.ssh/id_rsa. ↩↩↩↩↩↩↩↩↩↩↩↩↩

  3. « MCP Tool Poisoning, » OWASP Foundation. Catalogue l’empoisonnement d’outils comme une classe d’attaque nommée : des instructions cachées dans les métadonnées d’outils qui influencent un agent « même si l’outil empoisonné n’est jamais invoqué », et l’exemple GitHub MCP dans lequel une issue empoisonnée conduit un agent à lire des dépôts privés via le jeton du développeur et à les faire fuiter dans une pull request publique. ↩↩↩↩↩↩

  4. Sarah Young et Den Delimarsky, « Protecting against indirect prompt injection attacks in MCP, » Microsoft Developer Blog, 28 avril 2025. Recommande des « prompt shields » qui « utilisent des algorithmes avancés d’apprentissage automatique et de traitement du langage naturel pour détecter et filtrer les instructions malveillantes », le spotlighting où « l’inclusion de délimiteurs dans le message système délimite explicitement l’emplacement du texte d’entrée », la vérification de la chaîne d’approvisionnement des composants MCP, et une hygiène fondamentale comme le moindre privilège. ↩↩↩

Articles connexes

La sandbox de votre agent n'est qu'une suggestion

Un attaquant a ouvert une issue GitHub et glissé un malware dans la version suivante de Cline. Pourquoi les sandboxes d'…

23 min de lecture

Les serveurs MCP sont la nouvelle surface d'attaque

50 vulnérabilités MCP, 30 CVE en 60 jours, 13 critiques : les protocoles d'outils sont la surface d'attaque que personne…

10 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 …

14 min de lecture