Le SDK Python officiel de MCP laisse un serveur malveillant voler les identifiants OAuth
Une faille du SDK Python officiel du protocole MCP laisse un serveur malveillant rediriger le client secret, le code d’autorisation et la clé PKCE vers un point de terminaison qu’il contrôle. Passez aux versions 1.30.0 ou 2.2.0, renseignez le paramètre issuer et faites tourner vos secrets OAuth.
28 septembre 2026. Les mainteneurs du SDK Python officiel du protocole MCP publient un avis de sécurité : un serveur malveillant peut amener un client à lui remettre ses identifiants OAuth. 29 septembre 2026. The Hacker News relaie l’alerte, et Cycode, la société qui a découvert la faille, documente l’échange complet dans un test. 7 septembre 2026. Les correctifs — les versions 1.30.0 et 2.2.0 — étaient déjà sortis, présentés comme de simples « changements de comportement » plutôt que comme une correction de sécurité. Pourquoi c’est important : MCP est en train de devenir le câblage standard qui relie les agents d’IA aux outils, et ce câblage fait confiance au serveur sur la question la plus sensible qui soit — où envoyer vos secrets.
Un protocole réseau qui fait confiance à la mauvaise adresse
MCP, pour Model Context Protocol, est un standard ouvert qui connecte des applications d’IA à des outils et des données extérieurs, un peu comme un HTTP spécialisé dans les capacités d’agent. Son SDK Python officiel sert à bâtir aussi bien des serveurs que des clients MCP. Quand un client doit s’authentifier auprès d’un service, il interroge le serveur auquel il se connecte pour savoir où se trouve le service de connexion — l’authorization server.
C’est là que le bât blesse. Sur les versions vulnérables, le SDK ne vérifiait pas systématiquement cette réponse. Un serveur malveillant pouvait pointer le client vers un service de connexion de son choix, soit en désignant son propre serveur, soit en servant des détails de connexion qui nomment le vrai service de l’utilisateur tout en expédiant les secrets ailleurs. Le client, lui, obéissait.
Le défaut est donc un défaut de confiance protocolaire, pas un buffer overflow : la découverte du point de terminaison, qui devrait être une donnée dérivée et vérifiée, était traitée comme une information fournie par une partie potentiellement hostile. En termes réseau, c’est l’équivalent de remettre une clé à une adresse annoncée par la personne qui vient de vous la demander, sans vérifier que c’est bien votre porte.
Le scénario : le client remet ses secrets au mauvais terminal
Quand un client MCP s’authentifie, il transmet au service de connexion trois éléments : le client secret, le code d’autorisation et la clé de preuve PKCE. La clé PKCE est une valeur à usage unique conçue pour empêcher qu’un code d’autorisation volé soit rejoué — la remettre à l’attaquant neutralise donc aussi cette protection.
Le vol se déroule ainsi : le client demande au serveur l’adresse de son service de connexion, le serveur répond avec la sienne, et le client envoie ses trois secrets au mauvais destinataire. Avec ces éléments, l’attaquant demande un jeton d’accès valide au vrai service. Cycode a démontré l’échange complet en test : le jeton obtenu porte exactement les permissions que l’application s’était vu accorder. Comme le client secret est de longue durée, il reste exploitable tant qu’il n’est pas changé.
La gravité varie selon le fournisseur d’authentification. Le score CVSS est de 7,5 pour les deux fournisseurs machine-to-machine, qui s’authentifient sans aucune intervention humaine, et de 6,5 pour le fournisseur interactif, où une personne doit lancer la connexion — mais la page qu’elle approuve est la véritable page de connexion, donc rien ne paraît anormal. Aucun CVE n’avait été attribué au 29 septembre.
Qui est touché, qui ne l’est pas
Une application est vulnérable si elle utilise le SDK comme client MCP sur HTTP avec l’un des fournisseurs OAuth suivants — OAuthClientProvider, ClientCredentialsOAuthProvider, PrivateKeyJWTOAuthProvider, ou le fournisseur déprécié de la branche 1.x RFC7523OAuthClientProvider — et qu’elle peut se connecter à un serveur qu’elle ne contrôle pas entièrement tout en détenant des identifiants pour un vrai service de connexion.
En revanche, trois cas ne sont pas affectés : les serveurs MCP construits avec le SDK, les clients locaux en stdio, et les clients qui attachent leurs propres jetons.
| Branche | Versions affectées | Corrigée dans |
|---|---|---|
| 1.x | 1.9.1 à 1.29.1 | 1.30.0 |
| 2.x | 2.0.0 à 2.1.1 | 2.2.0 |
Dans les versions corrigées, le client détermine d’abord quel service de connexion il attend, avant de récupérer le moindre détail, et refuse toute réponse qui en nomme un autre. La vérification est ramenée à une comparaison contre une valeur connue, au lieu d’être acceptée d’une source non vérifiée.
Ce qu’il faut faire, au-delà de la mise à jour
Mettre à jour ne suffit pas toujours. Si vous utilisez ClientCredentialsOAuthProvider ou PrivateKeyJWTOAuthProvider, l’avis précise que la mise à jour ne change rien tant que vous ne passez pas aussi issuer= pour nommer le service de connexion auquel ces identifiants appartiennent. Sans ce paramètre, le client continue de suivre le serveur que MCP lui désigne.
Sur la version 1.30.0, l’avertissement correspondant est un simple DeprecationWarning, que Python masque par défaut : il passe donc facilement inaperçu. Et le fournisseur déprécié RFC7523OAuthClientProvider ne dispose d’aucune option issuer= — il faut migrer vers l’un des deux autres fournisseurs.
Trois gestes complètent la correction. Effacez une fois les enregistrements de client OAuth stockés, car les anciens ne sont liés à aucun service de connexion et le restent. Si un client a pu se connecter à un serveur non fiable, faites tourner son client secret et révoquez ses jetons auprès du service de connexion. Sur les anciennes versions, il n’existe aucun contournement : la seule parade est de ne se connecter qu’à des serveurs MCP de confiance.
Ce que ça change pour l’écosystème des agents
Cette faille arrive au moment où MCP s’installe comme l’infrastructure de facto des agents d’IA — des assistants de code aux plateformes qui exposent des API aux modèles. Or un protocole qui transporte des identifiants doit appliquer, dès sa conception, les leçons de OAuth : l’issuer est une donnée que le client doit connaître et imposer, pas une découverte qu’il accepte de la partie distante.
L’absence de CVE au moment de la publication est elle-même un signal. Les correctifs sont sortis le 7 septembre sous l’étiquette « changements de comportement », et l’avis n’a suivi que le 28 septembre — trois semaines pendant lesquelles les déploiements qui s’étaient contentés des notes de version n’avaient aucune raison de traiter la mise à jour comme urgente. Le décalage entre correctif technique et communication de sécurité est, pour un protocole en pleine adoption, un angle mort à surveiller.
Verdict
Si vous construisez un client MCP sur HTTP avec le SDK Python officiel, passez immédiatement en 1.30.0 ou 2.2.0 — c’est la correction non négociable, et elle est rétrocompatible. Si vous utilisez ClientCredentialsOAuthProvider ou PrivateKeyJWTOAuthProvider, la mise à jour seule ne suffit pas : ajoutez issuer= explicitement, puis purgez vos enregistrements de client stockés. Et si l’un de vos clients a déjà dialogué avec un serveur MCP non fiable, traitez le secret comme compromis : faites-le tourner, révoquez les jetons, et ne reprenez la connexion qu’une fois la vérification d’issuer en place. Tant que MCP reste aussi jeune, la règle de fond est simple — ne connectez un client qui détient des secrets qu’à des serveurs dont vous connaissez déjà l’issuer.