La prompt injection n’est pas une requête mal formée supprimable par expression régulière. C’est une rupture de confiance où une donnée modifie le comportement du modèle. Dans un agent, ce comportement devient appel d’outil, message, écriture de fichier ou requête externe. MCP facilite les outils, mais donne au texte non fiable davantage de chemins vers les systèmes privilégiés.
Cet article applique le OWASP GenAI LLM Top 10 2026 aux agents qui lisent du contenu externe et utilisent MCP. Il s’agit d’un modèle de menace et d’un guide d’ingénierie, pas d’un audit de sécurité. Aucun contrôle présenté ici ne garantit la sécurité. Il faut plutôt supposer qu’une injection influencera parfois le modèle, puis rendre l’action qui en résulte limitée, visible, réversible et difficile à détourner.
Pourquoi le modèle n’est pas une frontière de sécurité
Un LLM reçoit les instructions système, la demande de l’utilisateur, les documents récupérés, les descriptions et résultats d’outils, l’historique et la mémoire dans un même contexte. Les délimiteurs et les étiquettes peuvent exprimer une politique de confiance, mais ils ne créent pas une isolation architecturale. Le modèle peut mal interpréter une étiquette, prendre une phrase plausible dans un document pour une commande ou combiner plusieurs indices anodins en plan dangereux.
OWASP LLM01:2026 décrit la prompt injection comme un changement de comportement provoqué par une entrée directe, un contenu récupéré, un résultat d’outil, une image, un audio, une vidéo, un contexte intermédiaire ou une mémoire persistante. Cette catégorie est distincte de la divulgation d’informations sensibles, de l’agence excessive et du traitement dangereux des sorties, même si ces risques se combinent dans un incident. L’injection fournit l’influence, l’outil fournit le privilège, le secret est l’actif et une requête réseau, une URL ou une commande shell peut servir de canal d’exfiltration.
Le modèle ne devrait donc ni conserver les identifiants, ni décider de l’autorisation, ni être l’unique validateur d’une opération qui modifie l’état. Ces décisions doivent se trouver dans du code applicatif déterministe. Laissez au modèle l’interprétation et la planification, puis faites appliquer les permissions par le système qui l’entoure.
Modèle de menace pour un agent connecté à MCP
Commencez par le flux réel des données, et non par une architecture qui s’arrête au chat. Recensez l’utilisateur, le fournisseur du modèle, l’agent, le client et les serveurs MCP, le serveur d’autorisation, les API, le navigateur, les fichiers, la mémoire, l’index, les journaux et le réseau sortant. Marquez chaque liaison comme utilisateur, organisation, tiers, public ou inconnue.
Les attaquants possibles sont un site ou expéditeur malveillant, un contributeur de ticket ou dépôt, une dépendance ou un paquet MCP compromis, un opérateur malhonnête, ou un voleur de jeton ou de session. Un utilisateur légitime peut transmettre une injection en collant un document contenant des instructions destinées à un autre système. Une base interne peut recevoir une entrée par formulaire public, synchronisation ou compte compromis.
Énumérez séparément instructions, jetons, clés, données personnelles, code, documents privés, métadonnées cloud, configuration, mémoire et capacités d’envoi, suppression, achat, déploiement ou modification. Indiquez ce qui est lisible, modifiable ou observable. Un outil en lecture seule peut divulguer sa sortie vers une destination hostile, et une notification devient dangereuse si elle accepte des URL ou un corps arbitraire.
Pour chaque flux, écrivez l’invariant attendu en langage clair : « résumer le ticket sans suivre ses instructions », « lire uniquement ce dépôt », « rédiger un e-mail sans l’envoyer avant approbation ». Ajoutez la condition d’échec : secret présent dans un argument, scope trop large, écriture en dehors de l’espace de travail ou destination non approuvée.
Une fiche de risque contient cinq champs : surface, propagation, encodage, privilège et puits. La surface peut être le chat, le Web, un PDF, une description MCP, un résultat ou la mémoire. La propagation peut franchir des étapes, sessions ou agents. L’encodage peut être visible, HTML, Unicode invisible, multilingue, image, audio ou obfusqué. Le privilège est l’identité et les scopes à l’exécution. Le puits produit l’impact.
Injection directe et indirecte
L’injection directe passe par le chemin visible de l’utilisateur. Celui-ci peut demander à l’agent d’ignorer sa tâche, de révéler ses instructions, de lancer une commande sans restriction ou d’appeler un outil hors contexte. Elle inclut aussi un utilisateur honnête qui colle un texte contenant une instruction adressée à une IA. Le jailbreak est un cas où l’objectif est de contourner les protections du modèle, mais un agent peut être compromis sans jailbreak : exécuter poliment une fausse instruction de remboursement reste une violation de la limite applicative.
L’injection indirecte arrive dans un contenu que l’utilisateur n’a pas fourni comme instruction. Une page peut demander le téléversement du contexte de l’agent. Une pièce jointe peut demander une réinitialisation de mot de passe. Un ticket peut demander de rechercher un dépôt privé. Le payload peut se trouver dans une ligne de base, un titre d’issue, un README, une image ou un résultat d’outil. L’utilisateur peut ne jamais voir les octets cachés dans le HTML, les métadonnées, une section réduite, une image ou des caractères de largeur nulle.
MCP élargit cette surface de deux façons. Un serveur publie des noms, descriptions, schémas d’entrée, ressources et prompts que le client place dans le contexte du modèle. Une description empoisonnée peut demander d’appeler un autre outil en premier, d’ajouter un secret dans un argument ou de faire confiance à une URL contrôlée par l’attaquant. Le serveur renvoie ensuite un résultat que le modèle peut interpréter comme une nouvelle instruction et utiliser pour lancer un second appel. C’est un empoisonnement d’outil ou une injection par sortie, même si les messages JSON-RPC restent valides.
Traitez les métadonnées d’outils comme une influence exécutable, pas comme de la documentation. Verrouillez les versions des paquets, vérifiez les serveurs, relisez descriptions et schémas, comparez les releases et inventoriez les capacités autorisées de chaque serveur. Une signature confirme la provenance mais ne prouve pas qu’une version est saine. Il faut aussi examiner son implémentation et son comportement réseau.
De l’influence à l’exfiltration
La prompt injection devient une fuite lorsqu’elle relie une source à un puits. La source peut être une issue empoisonnée récupérée par l’agent. Le puits peut être une requête HTTP, un e-mail, un commentaire public, une invitation de calendrier, une URL d’image, un journal ou un argument d’outil. L’attaquant n’a pas besoin d’accéder directement à la donnée privée si l’agent peut la lire et communiquer à l’extérieur.
Modélisez explicitement la « triade létale » : contenu non fiable, données sensibles et canal externe ou modifiant l’état. Supprimer un des trois éléments est souvent plus robuste que de reconnaître chaque phrase malveillante. Un agent de recherche peut naviguer sur des pages publiques sans connexion et avec un réseau limité. Un agent de résumé peut lire des fichiers privés sans réseau ni capacité d’envoi. Un rédacteur d’e-mail peut préparer un brouillon sans droit d’expédition.
Le filtrage des sorties ne suffit pas. Un secret peut partir dans un champ JSON valide, un paramètre d’URL, un message de diagnostic, une image, des espaces, de l’Unicode ou un e-mail normal. Contrôlez la destination et les flux d’information avant le puits. Masquez les secrets dans les journaux et les traces, puis faites passer les requêtes sortantes par un proxy qui bloque les adresses privées, les domaines inconnus et les méthodes inattendues.
Autorisation MCP et contrôles OAuth
Pour un serveur MCP HTTP protégé, séparez les rôles. Le serveur MCP est le resource server, le client demande un accès pour le propriétaire de la ressource et l’authorization server émet les jetons. Suivez la spécification d’autorisation MCP et ses exigences OAuth adaptées à la version utilisée, au lieu d’inventer un flux de proxy.
Liez chaque jeton à la ressource MCP visée. La spécification impose l’URI canonique dans le paramètre OAuth resource des deux demandes et la validation de sa destination. Utilisez l’en-tête Authorization, jamais la chaîne de requête. Un serveur MCP ne doit ni accepter ni relayer un jeton d’une autre ressource. Pour une API en amont, utilisez un jeton distinct. Le passthrough détruit l’audience et l’audit et peut transformer le serveur en proxy d’exfiltration.
Protégez le code d’autorisation avec PKCE, des redirect URI enregistrées exactement, HTTPS en production et une valeur state aléatoire, à usage unique. Un proxy qui enregistre dynamiquement des clients doit obtenir le consentement pour chaque client avant de rediriger vers un serveur tiers. Liez le consentement à l’identifiant du client et aux scopes demandés. Une cookie générale indiquant que « l’application est approuvée » ne suffit pas et crée un confused deputy.
Considérez la découverte comme une entrée du serveur, non comme une configuration de confiance. Autorisez des schémas et hôtes approuvés, refusez javascript:, data: et file:. Contre la SSRF, bloquez les plages privées, loopback, link-local et cloud metadata, validez chaque redirection et utilisez un proxy de sortie. N’ouvrez pas les URL avec un shell. Une injection peut tenter d’exploiter ces chemins.
Utilisez des scopes progressifs. Commencez par découverte et lecture, demandez un scope précis au besoin et journalisez les sous-ensembles avec un identifiant de corrélation. Évitez *, all et les scopes omnibus. Les claims ne remplacent pas l’autorisation côté serveur. Des jetons courts, un stockage protégé et la rotation des refresh tokens publics limitent un vol.
Un serveur MCP local nécessite une autre limite. Le processus peut avoir les privilèges du client, lire des fichiers, utiliser le réseau et lancer des commandes. Affichez la commande de démarrage complète et ses arguments avant la connexion. Préférez stdio ou un IPC local protégé à un HTTP sans authentification. Exécutez le serveur dans un sandbox ou un conteneur avec des droits minimaux sur les fichiers, le réseau et les processus, puis accordez explicitement les répertoires et destinations supplémentaires.
Défenses en profondeur
Le moindre privilège réduit le rayon d’explosion. Donnez à chaque agent uniquement les outils d’un flux. Séparez lecture, rédaction, approbation et validation finale. Employez des identifiants courts et propres à l’opération plutôt qu’un jeton utilisateur permanent. Vérifiez encore l’autorisation à l’exécution, car le plan du modèle, la session, la description de l’outil ou la ressource peuvent avoir changé.
Une approbation doit être un vrai point de contrôle. Exigez-la pour envoyer, supprimer, publier, payer, modifier des droits, déployer, ouvrir une classe de données ou contacter une destination. Affichez action, arguments, identité, cible, champs transmis et effet, pas seulement le résumé du modèle. Recalculez l’aperçu et liez le consentement au hash de l’opération afin qu’une étape ne remplace pas les arguments. Limitez les actions à faible risque sans habituer à approuver des fenêtres opaques.
L’isolation limite ce qu’une injection atteint. Séparez locataires, sessions et mémoires. Un agent de navigation ne reçoit aucun identifiant privé. Pour le code, montez un espace étroit, interdisez le réseau par défaut et séparez l’identité d’installation. Combinez isolation du processus, des fichiers, du réseau et du navigateur. Vérifiez montages, sockets, identités, sorties et chemins d’évasion du conteneur.
La provenance rend les décisions vérifiables. Associez source, auteur, heure, intégrité et classe de confiance à chaque document, description et résultat. Conservez-les lors des résumés et transferts. Rendez l’externe comme une donnée avec l’étiquette « pas une instruction ». L’étiquette aide le modèle, mais le code impose les droits. Supprimez ou normalisez les caractères invisibles, en sachant que d’autres attaques restent possibles.
Validez la sortie dans du code de confiance avec des schémas stricts, une liste d’outils autorisés, des arguments typés, des contrôles d’URL et de chemin, des limites de taille et de fréquence et une machine d’état par flux. Ne transformez pas l’avis d’un second modèle en autorisation. Un critique peut signaler un comportement suspect, mais la décision finale doit être déterministe. Enregistrez prompts, sources, versions de métadonnées, arguments, décisions de politique, approbations et réponses sans stocker les secrets bruts.
Évaluations adversariales et exploitation
Évaluez la boucle complète de l’agent, pas seulement le prompt. Testez override direct, HTML caché, e-mail cité, dépôt et description MCP empoisonnés, résultat demandant un second appel, mémoire intersession, payload multilingue ou encodé, caractères invisibles, URL SSRF, mauvaise audience de jeton et substitution après approbation. Ajoutez du contenu légitime qui ressemble à une attaque pour mesurer faux positifs et réussite de la tâche.
Testez avec un attaquant adaptatif qui connaît classifieurs, étiquettes, schémas et règles. Faites varier mots, modalité, ordre, moment et destination. Un score statique peut être excellent alors qu’une autre route existe. Mesurez succès, appels non autorisés, octets sensibles vers un puits, élévations de scope, exactitude des approbations et délais de détection et révocation. Conservez les régressions à chaque changement. Le guide d’évaluation des agents IA peut documenter ce programme.
Comparez l’architecture avec le guide production AI agent architecture. Les détails OAuth sont regroupés dans MCP server TypeScript avec OAuth.
Liste de contrôle en cas d’incident
En cas de suspicion, arrêtez le flux et désactivez la plus petite capacité qui suffit. Conservez prompt, source, provenance, métadonnées et version de l’outil, arguments, métadonnées du jeton sans sa valeur, décisions, approbations, destinations et horaires. Classez la voie comme directe, indirecte, issue d’un outil ou persistante par mémoire. Recherchez le payload dans autres locataires, index, files, journaux et transferts.
Révoquez les identifiants présents dans le contexte ou les journaux, invalidez sessions et refresh tokens, puis bloquez la destination et le serveur MCP. Examinez les API en aval pour les lectures, écritures, messages ou grants OAuth non autorisés. Vérifiez que les arguments exécutés correspondent à l’aperçu approuvé.
Après le confinement, supprimez les entrées empoisonnées, restaurez les métadonnées fiables et ajoutez le chemin aux tests. Notez ce que le modèle a vu, la décision de politique, l’approbation et le contrôle défaillant. Prévenez incident et vie privée si une donnée a franchi une frontière. Une détection ultérieure ne rend pas l’événement inoffensif.
Ce que la protection ne peut pas promettre
La prompt injection reste évolutive, car les modèles n’imposent pas de séparation formelle entre instructions et données. Entraînement, classifieurs, délimiteurs, provenance, schémas et contrôle humain réduisent le risque, mais un attaquant peut changer mots, encodage, ordre ou modalité. La validation humaine souffre de fatigue et d’aperçus trompeurs. Un sandbox mal configuré ou un paquet verrouillé peut aussi devenir dangereux.
Il serait incorrect d’affirmer qu’un agent est immunisé. On peut affirmer qu’un flux défini possède des frontières explicites, des capacités minimales, des contrôles déterministes, des décisions observables, des échecs testés et une réponse préparée. Réévaluez ces hypothèses à chaque ajout de serveur MCP, d’outil, de mémoire, de modèle, de source ou de canal sortant. Ce texte est un guide d’ingénierie, pas une certification ni un audit de sécurité.
Sources
- OWASP GenAI LLM Top 10 2026
- Spécification d’autorisation MCP
- Bonnes pratiques de sécurité MCP
- OpenAI : Designing AI agents to resist prompt injection
- OpenAI : Understanding prompt injections
- Anthropic : Trustworthy agents in practice
- Google Cloud : AI security and safety for MCP servers
- Microsoft : Protecting against prompt injection attacks Un contrôle de sortie n’est pas un contrôle d’autorisation.