MoyenneCVE-2026-116685
SDK Python du Model Context Protocol : les transports de client HTTP suivaient les redirections cross-origin avec des en-têtes et corps personnalisés
Exploitable dans des cas précis ou avec un impact limité : à corriger à la prochaine mise à jour.
- Sévérité
- Moyenne5.9 / 10
- Publiée le
- 27. Oktober 2026
- Mise à jour
- 27. Oktober 2026
L'avis
Traduction automatique de l'avis officiel. En cas de doute, l'avis d'origine, plus bas, fait foi.
Résumé
Dans les versions affectées, les transports de client Streamable HTTP et SSE du SDK suivaient les redirections HTTP vers n'importe quel hôte. Si le point de terminaison MCP configuré répondait par une redirection vers une origine différente :
- les en-têtes personnalisés définis sur le client (par exemple une identifiante
X-API-Key) étaient envoyés à cette origine, et - sur une redirection
307ou308, le corps de la demande était également réenvoyé là-bas.
Les fournisseurs de clients OAuth du SDK suivaient les redirections lors de leurs propres demandes de découverte, d'enregistrement et de jeton de la même manière.
Un en-tête Authorization bearer isolé n'était pas exposé ; la bibliothèque HTTP le supprime déjà sur les redirections cross-origin.
Quiconque capable de faire rediriger un point de terminaison que vous faites confiance vers un autre endroit (une redirection obsolète vers un domaine expiré, une règle de proxy mal acheminée, une logique de redirection que l'attaquant peut influencer) pourrait capturer ce matériau. Un serveur qui est lui-même malveillant n'en tire aucun avantage de cette manière ; il reçoit déjà directement vos demandes.
Suis-je concerné ?
Oui, si votre code utilise le SDK en tant que client MCP via HTTP à travers l'une des :
streamable_http_client(sur 2.x égalementClientavec une URLhttp://ouhttps://)streamablehttp_clientousse_clientClientSessionGroupavec des paramètres de serveur HTTP- l'interne
create_mcp_http_clientd'aide
Cela inclut un client HTTP que vous avez fourni vous-même avec follow_redirects=True.
Versions affectées : 1.8.0 à 1.29.1, et 2.0.0 à 2.1.1.
Non concernés :
- serveurs MCP
- clients stdio
- un client que vous avez fourni avec
follow_redirectslaissé à sa valeur par défaut deFalse
Correction
Mettez à niveau vers mcp 1.30.0 (1.x) ou 2.2.0 (2.x) ou ultérieur ; aucun changement de code n'est nécessaire.
Les transports, ainsi que les propres demandes des fournisseurs OAuth, suivent désormais une redirection uniquement lorsqu'elle reste sur l'origine du point de terminaison (même schéma, hôte et port, ou une mise à niveau http vers https sur le même hôte) et conserve la méthode de demande. Toute autre redirection n'est pas suivie et la demande échoue avec une erreur désignant la cible (MCPError sur 2.x, httpx.HTTPStatusError sur 1.x), quel que soit le client HTTP utilisé par le transport. L'interne create_mcp_http_client d'aide ne active plus le suivi de redirection, donc le code l'appelant directement reçoit désormais la réponse de redirection à la place.
Si votre client atteint actuellement son serveur par le biais d'une redirection vers un autre hôte, y compris un serveur qui n'a pas besoin d'identifiants, il arrêtera de se connecter après la mise à niveau : définissez l'URL du point de terminaison sur la cible de la redirection.
Jusqu'à ce que vous puissiez mettre à niveau, fournissez votre propre client HTTP avec follow_redirects laissé à False (http_client= sur streamable_http_client ; httpx_client_factory= sur sse_client et streamablehttp_client ; ClientSessionGroup n'a pas un tel paramètre). Si un client a déjà pu suivre une redirection vers un hôte que vous ne contrôlez pas, faites tourner les identifiants qu'il portait.
Ceci restaure ce que cette corrige : les redirections vers n'importe quel hôte sont de nouveau suivies, emportant vos en-têtes personnalisés et, sur 307/308, le corps de la demande, demandes de jeton OAuth incluses. Privilégiez le fait de définir l'URL du point de terminaison sur la cible de la redirection. Si vous ne pouvez pas, et que vous acceptez de transmettre les identifiants vers la cible de la redirection, donnez au transport un client HTTP qui suit les redirections indépendamment de ce que le SDK demande :
import httpx2 # sur 1.x : import httpx et héritez de httpx.AsyncClient à la place
class FollowRedirectsAnyway(httpx2.AsyncClient):
"""Suit les redirections vers N'IMPORT quelle origine. Abandonne délibérément la protection de même origine du SDK."""
async def send(self, request, *, follow_redirects=False, **kwargs):
return await super().send(request, follow_redirects=True, **kwargs)
http_client = FollowRedirectsAnyway(timeout=httpx2.Timeout(30, read=300))
# streamable_http_client(url, http_client=http_client)
# sse_client / streamablehttp_client prennent une usine à la place :
def client_factory(headers=None, timeout=None, auth=None):
return FollowRedirectsAnyway(headers=headers, auth=auth,
timeout=timeout if timeout is not None else httpx2.Timeout(30, read=300))
# sse_client(url, httpx_client_factory=client_factory)
La gestion des redirections est alors celle de la bibliothèque HTTP, comme avant la correction : un en-tête Authorization isolé est toujours supprimé sur les sauts cross-origin et 301/302/303 deviennent GET. Ce n'est pas quelque chose que le SDK supporte ou testes.
Composants touchés
| Composant | Versions touchées | Corrigé en |
|---|---|---|
| mcpPython (pip) | >= 2.0.0, < 2.2.0 | 2.2.0 |
| mcpPython (pip) | >= 1.8.0, < 1.30.0 | 1.30.0 |
Vous utilisez une version touchée ? Passez à la version corrigée, puis redéployez.