flawopen.com/AI Security/mcp-typescript-sdk-bearer-token-audience-validation
SDK TypeScript do MCP aceitava tokens sem validar o público
A GHSA-rvq5-wwqv-78pq afeta servidores HTTP MCP que aceitam tokens sem conferir seu público. Atualize e habilite expectedResource, retornando o público verificado em AuthInfo.resource.[1]
Um segurança aceita um crachá válido, mas não confere para qual prédio ele dá acesso. Se o mesmo emissor fornece crachás para vários prédios, um crachá de outro prédio pode ser aceito. O servidor MCP precisa comparar o destino do crachá com sua própria URL de recurso.[1]
Conceitos Centrais e Termos
Público (`aud`)- O recurso ou serviço para o qual um token de acesso foi emitido. Assinatura válida ou introspecção bem-sucedida não prova, por si só, que o token se destinava a este servidor MCP.[1], [7]
`expectedResource`- Opção habilitada explicitamente no middleware corrigido. Com ela, o URL de recurso configurado é comparado ao recurso informado pelo verificador do token; divergências recebem HTTP 401.[1], [2], [7]
Mapeamentos de frameworks
- Referência CWE para a fraqueza descrita neste guia: CWE-863
Fluxo de Ataque Passo a Paso
Um emissor atende várias APIs
A implantação afetada usa autenticação bearer HTTP para MCP, e o servidor de autorização emite tokens para mais de um serviço. Um token destinado a outra API ainda pode estar assinado corretamente e dentro da validade.[1]
Atualize e vincule a validação ao recurso MCP
Use a versão corrigida, configure expectedResource com o identificador deste servidor e faça verifyAccessToken() retornar o público verificado como AuthInfo.resource. A atualização não habilita a opção; sem resource, todas as requisições recebem 401.[1], [2], [5], [3], [6], [7]
Pacotes e versões afetadas do MCP TypeScript SDK
| Pacote | Versões afetadas | Versão corrigida |
|---|---|---|
@modelcontextprotocol/sdk | 1.6.0 a 1.31.0 | 1.32.0 ou posterior |
@modelcontextprotocol/server | 2.0.0 a 2.2.0 | 2.3.0 ou posterior |
@modelcontextprotocol/express | 2.0.0 a 2.0.1 | 2.0.2 ou posterior |
@modelcontextprotocol/server-legacy | 2.0.0 a 2.3.0 | 2.3.1 ou posterior |
Qualquer pacote com validação própria de aud em verifyAccessToken() | O aplicativo pode já implementar a verificação que falta no helper. | Confirme que a comparação é estrita e usa o identificador de recurso pretendido. |
Código-Fonte: Vulnerável vs. Seguro
Este exemplo segue o formato documentado pelo SDK e a correção incorporada. verifyJwt representa o validador JWT ou chamada de introspecção já existente na aplicação. Antes da correção, o middleware não oferecia expectedResource nem comparava a audience; a versão corrigida compara o recurso configurado com AuthInfo.resource. Use o identificador exato que o servidor de autorização coloca em aud; o exemplo seleciona uma URL de audience na mesma origem e deixa o SDK comparar o recurso completo. Atualize o SDK 1.x para 1.32.0 ou posterior; no 2.x, use @modelcontextprotocol/server 2.3.0 ou posterior. Com Express, atualize também @modelcontextprotocol/express para 2.0.2 ou posterior. Como AuthInfo.resource é um URL, um valor aud simples que não seja URL não pode ser comparado por expectedResource: valide esse identificador rigorosamente em verifyAccessToken() e deixe expectedResource sem configuração nesse deployment. A implementação de verifyJwt é específica da aplicação e foi omitida; não há falsificação de token nem procedimento de exploração.[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); // A verificação JWT da aplicação
return {
token,
clientId: payload.sub,
scopes: payload.scopes,
expiresAt: payload.exp,
// O recurso não é retornado, e o helper afetado não tinha a opção 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); // A verificação JWT da aplicação
// aud pode ser uma string, uma lista ou estar ausente. Informe o recurso deste 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 Verificação de Segurança para Engenharia
- ✓Localize servidores HTTP MCP que usam
requireBearerAuth()ouverifyBearerToken()e confirme se o emissor fornece tokens a várias APIs.[1] - ✓Atualize o
@modelcontextprotocol/sdk1.x para 1.32.0 ou posterior; no 2.x use@modelcontextprotocol/server2.3.0 ou posterior e, com Express,@modelcontextprotocol/express2.0.2 ou posterior; atualizeserver-legacypara 2.3.1 ou posterior.[1], [3], [6] - ✓Defina
expectedResourcecom o identificador exato deste servidor MCP em configuração confiável, sem derivá-lo da requisição recebida.[1], [2], [7] - ✓Faça
verifyAccessToken()validar o token com o servidor de autorização confiável e retornar o audience verificado emAuthInfo.resource. Se o emissor usar um identificador de audience simples que não seja URL, valide-o rigorosamente no verificador e deixeexpectedResourcesem configuração; não adivinhe nem o converta em URL.[1], [2], [7] - ✓Teste que o token deste recurso funciona e que tokens de outro serviço, público ausente e público com esquema, host, porta ou caminho diferente recebem 401.[1], [2], [7]
- ✓Não considere a atualização suficiente:
expectedResourcefica desativado até ser configurado, e habilitá-lo semAuthInfo.resourcerejeita todas as requisições.[1] - ✓Monitore logs de acesso e telemetria de validação para detectar audiences inesperados; revogue ou rotacione credenciais somente quando as evidências indicarem possível uso indevido.[1]
Fontes
- Aviso GitHub GHSA-rvq5-wwqv-78pq
- Pull request #2930 do SDK: expectedResource no requireBearerAuth
- Notas da versão 1.32.0 do MCP TypeScript SDK
- MITRE CWE-863: autorização incorreta
- 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