flawopen.com/AI Security/mcp-typescript-sdk-bearer-token-audience-validation
El SDK TypeScript de MCP no validaba el público de los tokens bearer
GHSA-rvq5-wwqv-78pq afecta a servidores HTTP MCP que aceptan tokens sin comprobar su público. Actualice y habilite expectedResource; devuelva el público verificado en AuthInfo.resource.[1]
Un guardia acepta una credencial válida, pero no comprueba para qué edificio sirve. Si una misma entidad emite credenciales para varios edificios, puede aceptar una destinada al edificio vecino. El servidor MCP debe comparar el destino de la credencial con su propia URL de recurso.[1]
Conceptos Clave y Términos
Público (`aud`)- El recurso o servicio para el que se emitió un token de acceso. Una firma válida o una introspección correcta no demuestra que el token estuviera destinado a este servidor MCP.[1], [7]
`expectedResource`- Opción que se habilita en el middleware corregido. Compara la URL de recurso configurada con el recurso que informa el verificador del token; si no coinciden, responde HTTP 401.[1], [2], [7]
Mapeos de marcos
- Referencia CWE para la debilidad descrita en esta guía: CWE-863
Flujo de Ataque Paso a Paso
Un emisor presta servicio a varias API
La implementación afectada usa autenticación bearer HTTP para MCP y su servidor de autorización emite tokens para más de un servicio. Un token para otra API puede tener firma y vigencia correctas.[1]
Actualice y vincule la validación al recurso MCP
Use la versión corregida, configure expectedResource con el identificador de este servidor y haga que verifyAccessToken() devuelva el público verificado como AuthInfo.resource. Actualizar no activa la opción; sin resource, todas las solicitudes reciben 401.[1], [2], [5], [3], [6], [7]
Paquetes y versiones afectados
| Paquete | Versiones afectadas | Versión corregida |
|---|---|---|
@modelcontextprotocol/sdk | 1.6.0 a 1.31.0 | 1.32.0 o posterior |
@modelcontextprotocol/server | 2.0.0 a 2.2.0 | 2.3.0 o posterior |
@modelcontextprotocol/express | 2.0.0 a 2.0.1 | 2.0.2 o posterior |
@modelcontextprotocol/server-legacy | 2.0.0 a 2.3.0 | 2.3.1 o posterior |
Cualquier paquete con validación propia de aud en verifyAccessToken() | La aplicación quizá ya implemente la comprobación que falta en el helper. | Comprueba que la comparación sea estricta y use el identificador de recurso previsto. |
Código Fuente: Vulnerable vs. Seguro
El ejemplo sigue el formato documentado por el SDK y la corrección incorporada. verifyJwt representa el validador JWT o la llamada de introspección que ya tenga la aplicación. Antes del arreglo, el middleware no ofrecía expectedResource ni comparaba la audiencia; la versión corregida compara el recurso configurado con AuthInfo.resource. Use el identificador exacto que el servidor de autorización incluye en aud; el ejemplo selecciona una URL de audiencia del mismo origen y deja que el SDK compare el recurso completo. Actualice el SDK 1.x a 1.32.0 o posterior; en 2.x use @modelcontextprotocol/server 2.3.0 o posterior. Con Express, actualice también @modelcontextprotocol/express a 2.0.2 o posterior. Como AuthInfo.resource es una URL, un valor aud simple que no sea una URL no se puede comparar mediante expectedResource: valide estrictamente ese identificador dentro de verifyAccessToken() y deje expectedResource sin configurar en ese despliegue. La implementación de verifyJwt es propia de la aplicación y se omite; no se muestra falsificación de tokens ni un procedimiento de explotación.[1], [2], [5], [3], [6], [7]
import { requireBearerAuth } from '@modelcontextprotocol/sdk/server/auth/middleware/bearerAuth.js';
const mcpServerUrl = new URL('https://api.example.com/mcp');
const auth = requireBearerAuth({
verifier: {
async verifyAccessToken(token) {
const payload = await verifyJwt(token); // Verificación JWT de la aplicación
return {
token,
clientId: payload.sub,
scopes: payload.scopes,
expiresAt: payload.exp,
// No se devuelve ningún recurso y el helper afectado no tenía la opción expectedResource.
};
},
},
});
import { requireBearerAuth } from '@modelcontextprotocol/sdk/server/auth/middleware/bearerAuth.js';
const mcpServerUrl = new URL('https://api.example.com/mcp');
const auth = requireBearerAuth({
verifier: {
async verifyAccessToken(token) {
const payload = await verifyJwt(token); // Verificación JWT de la aplicación
// aud puede ser una cadena, una lista o no estar presente. Indica el recurso de este servidor.
const audience = [payload.aud ?? []].flat().find(
aud => URL.canParse(aud) && new URL(aud).origin === mcpServerUrl.origin,
);
const resource = audience ? new URL(audience) : undefined;
return {
token,
clientId: payload.sub,
scopes: payload.scopes,
expiresAt: payload.exp,
resource,
};
},
},
expectedResource: mcpServerUrl,
});
Lista de Verificación de Seguridad para Ingeniería
- ✓Busque servidores HTTP MCP que usen
requireBearerAuth()overifyBearerToken()y determine si su emisor proporciona tokens para varias API.[1] - ✓Actualice el SDK 1.x a 1.32.0 o posterior; en 2.x use
@modelcontextprotocol/server2.3.0 o posterior y, con Express,@modelcontextprotocol/express2.0.2 o posterior; actualiceserver-legacya 2.3.1 o posterior.[1], [3], [6] - ✓Configure
expectedResourcecon el identificador exacto de este servidor MCP en la configuración confiable, sin derivarlo de la solicitud entrante.[1], [2], [7] - ✓Haga que
verifyAccessToken()valide el token con el servidor de autorización de confianza y devuelva la audiencia verificada comoAuthInfo.resource. Si el emisor usa un identificador de audiencia simple que no es URL, valídelo estrictamente dentro del verificador y dejeexpectedResourcesin configurar; no lo adivine ni lo convierta en URL.[1], [2], [7] - ✓Pruebe que el token de este recurso funciona y que los tokens de otro servicio, sin público o con esquema, host, puerto o ruta diferentes reciben 401.[1], [2], [7]
- ✓No considere suficiente la actualización:
expectedResourcequeda desactivado hasta configurarlo, y sinAuthInfo.resourcese rechazan todas las solicitudes.[1] - ✓Revise los registros de acceso y la telemetría de validación para detectar audiencias inesperadas; revoque o rote credenciales solo si las pruebas indican un posible uso indebido.[1]
Fuentes
- Aviso de GitHub GHSA-rvq5-wwqv-78pq
- Pull request #2930: expectedResource para requireBearerAuth
- Notas de versión 1.32.0 del MCP TypeScript SDK
- MITRE CWE-863: autorización incorrecta
- MCP TypeScript SDK v2 pull request #2929: add expectedResource to bearer-token check
- MCP TypeScript SDK release notes for 2.3.0
- MCP TypeScript SDK server guide: bearer-token audience validation