flawopen.com/AI Security/mcp-python-sdk-oauth-issuer-confusion
Falha de validação de issuer OAuth no MCP Python SDK
A GHSA-qx49-fqc8-xw99 permitia que um servidor MCP HTTP influenciasse para onde clientes OAuth afetados do SDK Python poderiam enviar credenciais. Atualize para mcp 1.30.0 ou 2.2.0; provedores máquina a máquina precisam definir issuer=. Não há CVE atribuído.[1], [3], [8]
Uma empresa envia uma chave lacrada ao banco cujo endereço aparece em um cartão de diretório aprovado. O servidor MCP podia fornecer o cartão, e um caminho alternativo não verificava se a entrada pertencia ao banco esperado. A validação do emissor compara a identidade do cartão com o banco configurado como confiável antes de enviar a chave.[1], [2]
Conceitos Centrais e Termos
Cliente MCP- Aplicação que usa o Model Context Protocol para acessar ferramentas ou dados de um servidor MCP. Esta falha afeta o SDK Python usado como cliente HTTP com seus provedores OAuth.[1]
Emissor do servidor de autorização- Identificador estável do serviço OAuth que emite tokens. O cliente deve comparar os metadados descobertos com um emissor esperado de forma independente.[1], [2]
Protected Resource Metadata (PRM)- Metadados que podem identificar os servidores de autorização de um recurso protegido. O SDK também possui um caminho legado quando PRM não está disponível.[1], [2]
Mapeamentos de frameworks
Fluxo de Ataque Passo a Paso
Um cliente HTTP MCP mantém credenciais OAuth
A aplicação usa uma versão afetada de mcp e um dos provedores OAuth do SDK. Ela pode conectar-se a um servidor MCP não totalmente confiável enquanto mantém um segredo de cliente, uma chave de assinatura ou um cadastro de cliente armazenado.[1]
O servidor influencia a descoberta da autorização
mcp 1.9.1–1.29.1 não validava o issuer nem vinculava credenciais em todos os caminhos de descoberta. mcp 2.0.0–2.1.1 era afetado quando faltava PRM e ocorria o fallback legado, ou durante a descoberta após 403 insufficient_scope. Nas duas linhas, provedores máquina a máquina não tinham issuer= para vincular credenciais pré-provisionadas. O intervalo do pacote no aviso começa na versão de pré-lançamento 2.0.0a1 e é <2.2.0; portanto, os pré-lançamentos afetados de 2.0.0 também estão no escopo.[1], [3], [8]
O endpoint de token recebe credenciais
O cliente pode enviar um segredo de cliente, código de autorização e verificador PKCE, ou uma asserção assinada, a um endpoint escolhido por esses metadados. A credencial depende do provedor; isso é uma falha de exposição de credenciais, não uma afirmação de que todo cliente é afetado.[1], [2]
O impacto depende do provedor e das permissões
Quem recebe as credenciais ou tokens pode usá-los dentro do escopo autorizado. O aviso atribui CVSS 7,5 aos provedores sem interação; o provedor interativo recebe 6,5 porque uma pessoa precisa iniciar o login. O aviso informa que nenhum CVE foi atribuído.[1]
Matriz de versões e ações do OAuth no MCP Python SDK
| Configuração do cliente | Condição afetada documentada | Ação necessária |
|---|---|---|
Cliente HTTP OAuth com mcp 1.9.1–1.29.1 | Todos os caminhos de descoberta não validavam o issuer nem vinculavam as credenciais de forma consistente. | Atualize para mcp 1.30.0 ou posterior e confirme a versão implantada. |
Cliente HTTP OAuth com mcp 2.0.0–2.1.1 | Afetado quando falta PRM e ocorre o fallback legado, ou durante a descoberta de escalonamento 403 insufficient_scope. O intervalo do pacote no aviso começa na versão de pré-lançamento 2.0.0a1 e é <2.2.0; portanto, os pré-lançamentos afetados de 2.0.0 também estão no escopo. | Atualize para mcp 2.2.0 ou posterior e confirme a versão implantada. |
ClientCredentialsOAuthProvider ou PrivateKeyJWTOAuthProvider com credenciais provisionadas | As versões afetadas não ofereciam issuer= para vincular essas credenciais ao servidor de autorização esperado. | Após atualizar, defina issuer= explicitamente. Migre do RFC7523OAuthClientProvider obsoleto na linha 1.x. |
| Servidor criado pelo SDK, cliente stdio ou cliente que fornece seu próprio token/cabeçalho | Não afetado por este aviso. | Nenhuma ação para esta falha específica; reavalie se o aplicativo também usa um cliente HTTP OAuth afetado. |
Análise de Causa Raiz
A falha de confiança tinha duas partes relacionadas: os caminhos de descoberta afetados nem sempre comparavam o issuer dos metadados do servidor de autorização com um valor esperado independentemente do servidor MCP, e as credenciais armazenadas ou pré-provisionadas não eram vinculadas ao emissor correto. Assim, um servidor MCP malicioso ou comprometido podia direcionar a troca de token para um endpoint sob seu controle e receber material OAuth mantido pelo cliente. As correções determinam o emissor esperado antes da descoberta, rejeitam divergências e vinculam os registros armazenados a esse emissor; provedores máquina a máquina sem interação também exigem issuer= explícito.[1], [2]
Código-Fonte: Vulnerável vs. Seguro
O argumento issuer existe nas versões corrigidas do SDK. Ele vincula credenciais máquina a máquina ao servidor de autorização correto; não substitui a atualização, a limpeza de cadastros antigos sem vínculo ou a rotação de credenciais possivelmente expostas.[2], [3], [8]
Trecho de origem: 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 a versão mcp >= 1.30.0 (1.x) ou >= 2.2.0 (2.x).
Lista de Verificação de Segurança para Engenharia
- ✓Inventarie os clientes HTTP MCP e resolva a versão instalada do pacote
mcp, inclusive dependências transitivas e imagens de contêiner.[1] - ✓Atualize clientes 1.x para
mcp1.30.0 ou posterior, ou clientes 2.x para 2.2.0 ou posterior; confira o lockfile e o ambiente implantado.[1], [3], [8] - ✓Defina
issuer=emClientCredentialsOAuthProviderePrivateKeyJWTOAuthProvider; migre doRFC7523OAuthClientProviderlegado de 1.x, que não oferece essa opção.[1], [2] - ✓Apague cadastros OAuth armazenados antes do vínculo ao emissor e registre-os novamente. Se você inseriu um cadastro previamente, defina seu emissor explicitamente.[1], [2]
- ✓Orientação de implementação da FlawOpen: Trate servidores MCP não confiáveis como limites de confiança que recebem credenciais. Não conecte-os a clientes com segredos OAuth ou chaves de produção sem autorização explícita da política.[1]
- ✓Se um cliente afetado pode ter se conectado a um servidor não confiável, troque o segredo do cliente e revogue os tokens no servidor de autorização.[1]
- ✓Inclua testes de regressão para descoberta 1.x e 2.x, issuer divergente, ausência de PRM,
403 insufficient_scope, cadastros vinculados ao issuer e provedores máquina a máquina semissuer=.[2] - ✓Revise o escopo deste aviso antes de classificar outros clientes como afetados: servidores MCP criados pelo SDK, clientes stdio e clientes que fornecem seus próprios tokens ou cabeçalhos não são afetados.[1]
Fontes
- 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