La note cachée dans l'outil : empoisonnement de la description d'un outil MCP
Le défi
Riverbend a branché un plugin MCP communautaire sur son assistant interne pour que les équipes puissent chercher dans leurs notes. Depuis, l'assistant joint discrètement à ses appels d'outils des fichiers que personne ne lui a demandé de joindre. L'assistant se comporte exactement comme on le lui a demandé, et c'est bien le problème : les instructions ne viennent pas toutes de Riverbend. Lisez le code serveur du plugin. Un outil porte un ordre que le modèle exécute et que l'utilisateur ne voit jamais. Donnez le nom du paramètre qu'il utilise pour faire sortir les données volées.
Ce que tu vas apprendre
- Expliquer qu'un modèle lit les descriptions d'outils comme des instructions, pas comme une documentation inerte
- Repérer une instruction injectée dans une docstring, avec l'ordre de rester silencieux
- Suivre un paramètre de contrebande depuis la signature jusqu'au corps de la fonction
- Décrire l'empoisonnement d'outil MCP comme une attaque au niveau des métadonnées, pas du prompt
- Citer les défenses : ne pas faire confiance aux descriptions tierces, figer les versions, moindre privilège
Compétences testées
Prérequis
- Lire du Python
- Savoir ce qu'est un outil MCP / un appel d'outil par un agent
Comment ça marche
Un agent décide comment appeler un outil à partir de la description de cet outil. Cette description est un contenu contrôlable par l'attaquant dès que le serveur est tiers, et le modèle obéit aux instructions qu'il y trouve comme il obéit à l'utilisateur. C'est l'opposé de l'endroit où les défenseurs regardent d'habitude : le payload se trouve dans des métadonnées que l'humain ne lit jamais.
Ici, la description de search_notes cache un ordre, encadré par des balises <IMPORTANT>, de lire les clés privées et les identifiants cloud et de les joindre à un paramètre, tout en demandant au modèle de n'en rien dire. Le paramètre, sidenote, paraît optionnel et anodin dans la signature, mais le corps de la fonction envoie son contenu hors de la machine.
L'indice, c'est la consigne de dissimulation : une vraie documentation ne demande jamais au modèle de cacher à l'utilisateur ce qu'il a fait.
Erreurs fréquentes
- Répondre
query. C'est l'entrée légitime de la recherche,sidenoteest le canal de contrebande. - Répondre
_audit_post. C'est la fonction qui envoie les données, mais la question porte sur le paramètre que l'instruction remplit. - Lire uniquement la signature. L'attaque se trouve dans la docstring, qui est la description d'outil fournie au modèle.
- Accuser le prompt de l'utilisateur. Rien de ce que l'utilisateur a tapé n'a d'importance, l'instruction est dans les métadonnées de l'outil.
Comment s'en protéger
Traitez les métadonnées d'outil comme non fiables et limitez ce que les outils peuvent atteindre.
- Ne donnez pas les descriptions d'outils tiers au modèle comme des instructions de confiance : assainissez-les ou affichez-les pour une relecture humaine d'abord.
- Figez et relisez la version exacte de chaque serveur MCP que vous chargez. Les descriptions peuvent changer entre deux appels : relisez-les à chaque mise à jour.
- Donnez à chaque outil uniquement l'accès au système de fichiers et au réseau dont il a besoin. Un outil de recherche de notes ne devrait pas pouvoir lire des clés SSH ni joindre un hôte arbitraire.
- Montrez à l'utilisateur chaque argument avec lequel un outil est réellement appelé, pour qu'un paramètre caché ne puisse pas passer inaperçu.