flawopen.com/AI Security/mcp-python-sdk-oauth-issuer-confusion
Fallo de validación del emisor OAuth en MCP Python SDK
GHSA-qx49-fqc8-xw99 permitía que un servidor MCP HTTP influyera en el destino al que los clientes OAuth afectados del SDK de Python podían enviar credenciales. Actualice a mcp 1.30.0 o 2.2.0; los proveedores máquina a máquina deben definir issuer=. No hay CVE asignado.[1], [3], [8]
Una empresa envía una llave sellada al banco cuya dirección figura en una tarjeta de directorio aprobada. El servidor MCP podía proporcionar la tarjeta y una ruta alternativa no comprobaba que la entrada perteneciera al banco esperado. La validación del emisor compara la identidad de la tarjeta con el banco configurado como confiable antes de enviar la llave.[1], [2]
Conceptos Clave y Términos
Cliente MCP- Aplicación que usa Model Context Protocol para conectarse a herramientas o datos de un servidor MCP. Este fallo afecta al SDK de Python cuando se usa como cliente HTTP con sus proveedores OAuth.[1]
Emisor del servidor de autorización- Identificador estable del servicio OAuth que emite tokens. El cliente debe comparar los metadatos descubiertos con un emisor que espere de forma independiente.[1], [2]
Protected Resource Metadata (PRM)- Metadatos que pueden identificar servidores de autorización para un recurso protegido. El SDK también dispone de una ruta heredada cuando falta PRM.[1], [2]
Mapeos de marcos
Flujo de Ataque Paso a Paso
Un cliente HTTP MCP conserva credenciales OAuth
La aplicación usa una versión afectada de mcp y uno de los proveedores OAuth del SDK. Puede conectarse a un servidor MCP no plenamente confiable mientras conserva un secreto de cliente, una clave de firma o un registro de cliente almacenado.[1]
El servidor influye en el descubrimiento de autorización
mcp 1.9.1–1.29.1 no validaba el emisor ni vinculaba credenciales en todas las rutas de descubrimiento. mcp 2.0.0–2.1.1 estaba afectado cuando faltaba PRM y se usaba la alternativa heredada, o durante el descubrimiento tras 403 insufficient_scope. En ambas ramas, los proveedores máquina a máquina carecían de issuer= para vincular credenciales preconfiguradas. El intervalo del paquete indicado por el aviso empieza en la versión preliminar 2.0.0a1 y es <2.2.0; por tanto, las versiones preliminares afectadas de 2.0.0 también están incluidas.[1], [3], [8]
El endpoint de tokens recibe credenciales
El cliente puede enviar un secreto de cliente, un código de autorización y el verificador PKCE, o una aserción firmada, a un endpoint elegido mediante esos metadatos. La credencial depende del proveedor; no significa que todos los clientes estén afectados.[1], [2]
El impacto depende del proveedor y los permisos
Quien recibe las credenciales o los tokens puede usarlos dentro del ámbito autorizado. El aviso puntúa con CVSS 7,5 a los proveedores desatendidos; el proveedor interactivo recibe 6,5 porque una persona debe iniciar el inicio de sesión. El aviso indica que no se ha asignado ningún CVE.[1]
Fijar el emisor cierra la brecha de confianza
Las versiones corregidas determinan el emisor esperado antes del descubrimiento, rechazan metadatos incompatibles y vinculan los registros almacenados a ese emisor. Los proveedores máquina a máquina también requieren un issuer= explícito.[1], [2], [3], [8]
Matriz de versiones y acciones de OAuth en MCP Python SDK
| Configuración del cliente | Condición afectada documentada | Acción requerida |
|---|---|---|
Cliente HTTP OAuth con mcp 1.9.1–1.29.1 | Todas las rutas de descubrimiento carecían de validación del emisor y de una vinculación uniforme entre credenciales y emisor. | Actualice a mcp 1.30.0 o posterior y compruebe la versión desplegada. |
Cliente HTTP OAuth con mcp 2.0.0–2.1.1 | Afectado si falta PRM y se usa la alternativa heredada, o durante el descubrimiento de escalado 403 insufficient_scope. El intervalo del paquete indicado por el aviso empieza en la versión preliminar 2.0.0a1 y es <2.2.0; por tanto, las versiones preliminares afectadas de 2.0.0 también están incluidas. | Actualice a mcp 2.2.0 o posterior y compruebe la versión desplegada. |
ClientCredentialsOAuthProvider o PrivateKeyJWTOAuthProvider con credenciales preconfiguradas | Las versiones afectadas no ofrecían issuer= para vincular estas credenciales con el servidor de autorización previsto. | Tras actualizar, establezca issuer= explícitamente. Migre desde RFC7523OAuthClientProvider, obsoleto en la rama 1.x. |
| Servidor creado con el SDK, cliente stdio o cliente que aporta su propio token/cabecera | No está afectado por este aviso. | No requiere acciones para este fallo concreto; vuelva a evaluar si la aplicación también usa un cliente HTTP OAuth afectado. |
Análisis de Causa Raíz
El fallo de confianza tenía dos partes relacionadas: algunas rutas de descubrimiento afectadas no comparaban de forma coherente el issuer de los metadatos del servidor de autorización con un emisor esperado de manera independiente del servidor MCP, y las credenciales almacenadas o aprovisionadas previamente no quedaban vinculadas a su emisor previsto. Por ello, un servidor MCP malicioso o comprometido podía dirigir el intercambio de tokens a un endpoint bajo su control y recibir material OAuth del cliente. Las correcciones determinan el emisor esperado antes del descubrimiento, rechazan las discrepancias y vinculan los registros almacenados a ese emisor; los proveedores máquina a máquina sin interacción también requieren un issuer= explícito.[1], [2]
Código Fuente: Vulnerable vs. Seguro
El argumento issuer está disponible en las versiones corregidas del SDK. Vincula las credenciales máquina a máquina con su servidor de autorización; no sustituye la actualización, la eliminación de registros antiguos sin vínculo ni la rotación de credenciales que podrían haberse expuesto.[2], [3], [8]
Fragmento de origen: mcp.client.auth
import os
from mcp.client.auth import ClientCredentialsOAuthProvider
auth = ClientCredentialsOAuthProvider(
client_id=os.environ["MCP_CLIENT_ID"],
client_secret=os.environ["MCP_CLIENT_SECRET"],
)
import os
from mcp.client.auth import ClientCredentialsOAuthProvider
auth = ClientCredentialsOAuthProvider(
client_id=os.environ["MCP_CLIENT_ID"],
client_secret=os.environ["MCP_CLIENT_SECRET"],
issuer=os.environ["MCP_AUTH_ISSUER"],
)
# Use mcp >= 1.30.0 (1.x) o >= 2.2.0 (2.x).
Lista de Verificación de Seguridad para Ingeniería
- ✓Inventaríe los clientes HTTP MCP y determine la versión instalada de
mcp, incluidas las dependencias transitivas y las imágenes de contenedor.[1] - ✓Actualice los clientes 1.x a
mcp1.30.0 o posterior, y los 2.x a 2.2.0 o posterior; compruebe el archivo de bloqueo y el entorno desplegado.[1], [3], [8] - ✓Configure
issuer=enClientCredentialsOAuthProvideryPrivateKeyJWTOAuthProvider; migre desdeRFC7523OAuthClientProviderde 1.x, que está obsoleto y no ofrece esa opción.[1], [2] - ✓Elimine los registros OAuth almacenados antes de vincularlos al emisor y vuelva a registrarlos. Si insertó un registro previamente, establezca su emisor explícitamente.[1], [2]
- ✓Recomendación de implementación de FlawOpen: Trate los servidores MCP no confiables como límites de confianza que reciben credenciales. No los conecte a clientes con secretos OAuth o claves de producción salvo que la política lo autorice.[1]
- ✓Si un cliente afectado pudo conectarse a un servidor no confiable, rote el secreto del cliente y revoque los tokens en el servidor de autorización.[1]
- ✓Añada pruebas de regresión para las rutas de descubrimiento 1.x y 2.x, emisores no coincidentes, ausencia de PRM,
403 insufficient_scope, registros vinculados al emisor y proveedores máquina a máquina sinissuer=.[2] - ✓Revise el alcance de este aviso antes de declarar afectados a otros clientes: los servidores creados con el SDK, los clientes stdio y los clientes que aportan sus propios tokens o encabezados no están afectados.[1]
Fuentes
- GitHub-reviewed advisory GHSA-qx49-fqc8-xw99
- MCP Python SDK pull request #3398: Validate issuer on every discovery path
- MCP Python SDK v1.30.0 release notes
- MITRE CWE-345: Insufficient Verification of Data Authenticity
- The Hacker News: Official MCP Python SDK flaw can let malicious servers steal OAuth credentials
- Cycode disclosure: MCP Python SDK OAuth flaw
- CWE-522: Insufficiently Protected Credentials
- MCP Python SDK v2.2.0 release