Retour au blog
Sécurité

Google, JPMorgan et l'État français ont livré le même bug MCP. Personne n'a demandé qui contrôle l'argument

7 octobre 2026 6 min de lecture

Le lundi 5 octobre, Ars Technica a publié un article dont le titre m'a arrêté net : « MCP for agent-to-agent comms may be the riskiest protocol you've never heard of ». Je travaille avec le Model Context Protocol des deux côtés : j'expose des serveurs MCP, et je fais tourner un client MCP qui consomme ceux des autres. Je suis donc allé plus loin que l'article, jusqu'au compte rendu du chercheur, aux fiches CVE et aux pull requests qui ont corrigé les bugs. L'histoire y est plus utile que dans le titre.

Le même bug, cinq fois

Le chercheur s'appelle Syed Anas Mohiuddin, et il se présente comme indépendant : ni employeur, ni labo, ni équipe. Sa mise à jour d'octobre liste cinq organisations dont les équipes de sécurité ont chacune confirmé et corrigé la même erreur : Google, JPMorgan Chase, Weaviate, la direction interministérielle du numérique française (DINUM) et l'administration de la ville de Tangerang, en Indonésie.

L'erreur, c'est la falsification de requête côté serveur (SSRF). Un outil reçoit un argument, l'argument devient une URL ou un chemin, et le serveur va le chercher depuis sa propre position réseau sans vérifier où il atterrit vraiment.

Le cas de Google est la CVE-2026-14540, publiée le 31 juillet avec Google comme autorité de numérotation. Son MCP Toolbox, des versions 0.3.0 à 1.4.0, construisait son client HTTP sans politique CheckRedirect et sans validation de l'IP cible, si bien qu'un paramètre de chemin forgé pouvait lui faire suivre une redirection vers un point d'accès interne. Le score CVSS 4.0 est de 8,0, High. Le correctif, fusionné le 18 juin, vérifie l'adresse résolue au moment de la connexion pour contrer le DNS rebinding, ajoute des listes d'IP autorisées et bloquées, et rejette une URL de base dangereuse au démarrage plutôt qu'à la première requête.

Le cas de JPMorgan est celui dont j'ai le plus appris. Son serveur MCP de documentation sur les paiements avait deux outils qui vont chercher du contenu. L'un, read_documentation, appliquait une liste blanche de domaines. Son voisin, related(), allait chercher n'importe quelle URL fournie par l'appelant. La pull request qui l'a corrigé le 18 septembre fait passer les deux outils par un seul chemin de récupération « pour que les deux outils ne puissent plus se désynchroniser ».

Le cas français montre d'où vient une mauvaise valeur : le serveur MCP officiel de data.gouv.fr allait chercher l'URL d'une documentation dans le catalogue de données ouvertes, un champ que n'importe quel producteur de données inscrit peut renseigner. Le correctif, fusionné le 4 septembre, valide l'IP de destination à la connexion et revérifie chaque saut de redirection.

Rapid7 ajoute un bug différent : la CVE-2026-97228, publiée le 25 septembre, une injection GraphQL via un identifiant d'export non validé dans son serveur MCP Bulk Export, notée 2,7, Low, corrigée en 0.6.2. L'avis de Rapid7 nomme lui-même l'exposition réaliste : « un client MCP en amont compromis ou négligent, ou une injection de prompt indirecte qui transmet un identifiant non validé ».

Il a aussi déposé cinq rapports sur des serveurs MCP fédéraux américains le 2 septembre. Ils sont toujours en cours de tri, donc je les laisse de côté.

Pourquoi des équipes qui n'ont rien en commun ont fait la même erreur

Sa thèse tient en une phrase : « Le développeur traite les données qui franchissent la frontière MCP, dans un sens comme dans l'autre, comme fiables parce qu'elles viennent de l'intérieur du système ».

Dans un agent, ça ne tient pas. L'argument d'un outil est écrit par un modèle qui vient de lire une page web, un document ou un e-mail que n'importe qui aurait pu rédiger. Douglas McKee, directeur du renseignement sur les vulnérabilités chez Rapid7, a dit à Ars que tout ce qu'un LLM transmet à ton outil « doit être traité comme une entrée venant d'un inconnu sur Internet ».

Sur la page Tools de la spec MCP actuelle, version 2026-07-28, les exigences de sécurité côté serveur tiennent en quatre courtes puces, à commencer par « Valider toutes les entrées des outils ». Les consignes détaillées sur la SSRF (bloquer les plages privées, valider chaque cible de redirection, se méfier du DNS rebinding, envisager un proxy de sortie) se trouvent dans la page Security Best Practices, et elles sont écrites pour les URL liées à OAuth qu'un client MCP récupère pendant la découverte d'autorisation. Si ton outil transforme un argument en URL, la meilleure checklist de la spec est une checklist que tu dois reporter toi-même.

Protocol Pivoting, sans la recette

À propos de ce titre : à strictement parler, MCP relie un agent à des outils et à des données, et A2A, un protocole lancé par Google et donné à la Linux Foundation, relie des agents à d'autres agents. Les déploiements réels enchaînent les deux : un orchestrateur délègue à des agents spécialisés via A2A, et chaque spécialiste a ses propres serveurs MCP.

L'article de Mohiuddin de mai appelle Protocol Pivoting la classe d'attaque qui en résulte. Un texte que contrôle l'attaquant arrive dans un résultat d'outil. L'orchestrateur le transforme en tâche déléguée. Le spécialiste fait confiance à son orchestrateur et agit avec ses propres identifiants et sa propre position réseau. L'hôte MCP a validé l'appel d'outil, et A2A a authentifié l'orchestrateur. Selon les mots de l'article, « aucune des deux défenses au niveau du protocole ne valide le contenu de la délégation entre protocoles ». C'est le vieux problème du confused deputy, avec un agent dans le rôle du délégué.

Tout le monde n'aime pas le nouveau nom. Markus Vervier, de X41 D-Sec, a dit à Ars que c'est de l'injection de prompt indirecte, et que le second protocole n'est « pas strictement nécessaire ». Sur la mécanique, je suis d'accord avec lui. Le nom reste utile, parce qu'il indique où va le correctif : pas à l'intérieur d'un protocole, mais au passage de relais entre deux.

Ce que je demande à n'importe quelle stack MCP, la mienne comprise

La LegalTech que je construis traite des documents confidentiels, donc je ne décrirai pas comment elle est câblée. Voici plutôt les questions.

Qui contrôle chaque argument ? Liste chaque outil, chaque argument et la source de sa valeur : l'utilisateur, le modèle ou des données en amont. Tout ce que contrôle le modèle ou une donnée en amont est une entrée d'inconnu. Si ça devient une URL, un hôte ou un chemin, fais-le passer par un seul client HTTP gardé : résoudre et vérifier l'IP à la connexion, aucune redirection automatique, une liste blanche des hôtes dont la fonctionnalité a besoin, et un échec franc au démarrage sur une mauvaise URL de base. Un seul client, pour qu'un outil voisin écrit le trimestre prochain ne puisse pas sauter la vérification.

Un identifiant est-il un nom ou une clé ? La spec le dit clairement dans ses consignes sur les outils à état : « un handle est un nom, pas une capacité ». Vérifie l'autorisation de l'appelant dessus à chaque appel, et passe-le comme variable liée, jamais par interpolation de chaîne, ce qui est exactement la façon dont Rapid7 a corrigé son bug.

Qu'a le droit de déclencher un résultat d'outil ? Un résultat d'outil est une donnée, pas une délégation. Un contenu venu de l'extérieur peut être affiché ou résumé, mais il ne devrait pas lancer une écriture, une requête sortante ou une tâche pour un autre agent dans la même exécution sans qu'un humain ou une politique explicite dise oui. La spec dit déjà que les clients devraient montrer les entrées d'un outil à l'utilisateur avant d'appeler un serveur et garder un humain en mesure de refuser les invocations. L'article propose d'étiqueter chaque morceau de contexte avec son origine et d'associer les origines aux actions permises. Un classifieur qui repère le texte d'allure impérative aide, mais j'utilise ailleurs un petit modèle juge pour les décisions oui ou non, et une probabilité est un fil de détente, pas un mur.

La délégation réduit-elle le périmètre ? La spec dit que les serveurs MCP « ne doivent accepter aucun jeton qui n'a pas été explicitement émis pour le serveur MCP ». La même logique devrait valoir entre agents : un sous-agent qui travaille sur une tâche déléguée reçoit ce dont la tâche a besoin, pas tout ce que son propre compte de service peut faire.

Qu'est-ce qui atterrit dans tes logs ? Le second mode de défaillance du compte rendu n'a besoin d'aucun attaquant : dans un cas fédéral encore en tri, un serveur journalise les corps complets des erreurs en amont, qui peuvent contenir des données personnelles. Avec des documents confidentiels, c'est le bug que je chercherais en premier.

Lundi

Ouvre tes serveurs MCP et cherche chaque requête sortante. Pour chacune, note qui contrôle la destination. Si la réponse est « le modèle » ou « ce que l'amont a renvoyé », tu as sous les yeux le bug que cinq équipes sans rapport ont livré cette année.

La phrase de McKee à Ars résume tout : « Chaque maillon de cette chaîne a fait exactement ce pour quoi il avait été conçu ». MCP rend très facile d'exposer une fonction à un agent. Demander qui contrôle chaque argument reste notre travail.

Sources

Un projet du même genre ?

Je conçois et déploie des produits comme celui-ci. Parlons-en.

Discutons