flawopen.com/AI Security/mcp-typescript-sdk-bearer-token-audience-validation
TypeScript SDK MCP не проверял аудиторию Bearer-токенов
GHSA-rvq5-wwqv-78pq затрагивает HTTP-серверы MCP, принимавшие токены без проверки аудитории. Обновите SDK, включите expectedResource и возвращайте проверенную аудиторию в AuthInfo.resource.[1]
Охранник принимает действительный пропуск, но не смотрит, в какое здание он открывает вход. Если один центр выдаёт пропуска в несколько зданий, может пройти пропуск для соседнего здания. Сервер MCP должен сверить назначение пропуска со своим URL ресурса.[1]
Ключевые понятия и термины
Аудитория (`aud`)- Ресурс или служба, для которых выдан токен доступа. Корректная подпись или успешная интроспекция сами по себе не доказывают, что токен предназначен этому серверу MCP.[1], [7]
`expectedResource`- Явно включаемая настройка исправленного middleware. Она сравнивает настроенный URL ресурса со значением, которое сообщает проверяющий токен, и отклоняет несовпадение с HTTP 401.[1], [2], [7]
Связи со стандартами
- Ссылка CWE для слабого места, описанного в этом руководстве: CWE-863
Пошаговый сценарий атаки
Один издатель обслуживает несколько API
В затронутой конфигурации используется HTTP Bearer-аутентификация MCP, а сервер авторизации выдаёт токены для нескольких служб. Токен для другого API при этом может быть правильно подписан и не просрочен.[1]
Обновитесь и привяжите проверку к ресурсу MCP
Установите исправленную версию, задайте expectedResource для этого сервера и возвращайте проверенную аудиторию из verifyAccessToken() как AuthInfo.resource. Само обновление опцию не включает; без resource все запросы получат 401.[1], [2], [5], [3], [6], [7]
Затронутые пакеты MCP TypeScript SDK
| Пакет | Затронутые версии | Исправленная версия |
|---|---|---|
@modelcontextprotocol/sdk | 1.6.0–1.31.0 | 1.32.0 или новее |
@modelcontextprotocol/server | 2.0.0–2.2.0 | 2.3.0 или новее |
@modelcontextprotocol/express | 2.0.0–2.0.1 | 2.0.2 или новее |
@modelcontextprotocol/server-legacy | 2.0.0–2.3.0 | 2.3.1 или новее |
Любой пакет с собственной проверкой aud в verifyAccessToken() | В приложении уже может быть реализована проверка, отсутствующая в helper. | Убедитесь, что сравнение точное и использует ожидаемый идентификатор ресурса. |
Исходный код: Уязвимый vs Защищённый вариант
Пример соответствует документированному формату SDK и внесённому исправлению. verifyJwt обозначает уже используемый в приложении JWT-проверяющий код или вызов интроспекции. До исправления middleware не имел expectedResource и не сравнивал аудиторию; исправленная версия сравнивает настроенный ресурс с AuthInfo.resource. Используйте точный идентификатор, который сервер авторизации помещает в aud; пример выбирает URL аудитории с тем же origin и поручает SDK сравнить полный ресурс. Обновите SDK 1.x до 1.32.0 или новее; для 2.x используйте @modelcontextprotocol/server 2.3.0 или новее. При использовании Express обновите и @modelcontextprotocol/express до 2.0.2 или новее. Поскольку AuthInfo.resource имеет тип URL, простое значение aud, не являющееся URL, нельзя сравнить через expectedResource: строго проверяйте этот идентификатор внутри verifyAccessToken() и не задавайте expectedResource для такого развертывания. Реализация verifyJwt зависит от приложения и опущена; подделка токенов и процедура эксплуатации не приводятся.[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); // Проверка JWT приложением
return {
token,
clientId: payload.sub,
scopes: payload.scopes,
expiresAt: payload.exp,
// Ресурс не возвращается, а у уязвимого helper не было параметра 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); // Проверка JWT приложением
// aud может быть строкой, списком или отсутствовать. Укажите ресурс этого сервера.
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,
});
Чек-лист по защите системы для инженеров
- ✓Найдите HTTP-серверы MCP с
requireBearerAuth()илиverifyBearerToken()и выясните, выдаёт ли их сервер авторизации токены для нескольких API.[1] - ✓Обновите SDK 1.x до 1.32.0 или новее; для 2.x используйте
@modelcontextprotocol/server2.3.0 или новее и, при Express,@modelcontextprotocol/express2.0.2 или новее;server-legacyобновите до 2.3.1 или новее.[1], [3], [6] - ✓Задайте
expectedResourceравным точному идентификатору этого сервера MCP в доверенной конфигурации; не получайте его из входящего запроса.[1], [2], [7] - ✓Пусть
verifyAccessToken()проверяет токен у доверенного сервера авторизации и возвращает проверенную аудиторию вAuthInfo.resource. Если издатель использует простой идентификатор аудитории, не являющийся URL, строго проверяйте его в самом проверяющем коде и не задавайтеexpectedResource; не угадывайте значение и не преобразуйте его в URL.[1], [2], [7] - ✓Проверьте, что токен для этого ресурса принимается, а токен другой службы, отсутствие аудитории и отличия схемы, хоста, порта или пути приводят к 401.[1], [2], [7]
- ✓Одного обновления недостаточно:
expectedResourceвыключен, пока его не настроили; безAuthInfo.resourceвсе запросы будут отклонены.[1] - ✓Проверяйте журналы доступа и телеметрию валидации на наличие неожиданных аудиторий; отзывайте или меняйте учётные данные только при наличии признаков возможного злоупотребления.[1]
Источники
- Уведомление безопасности GitHub GHSA-rvq5-wwqv-78pq
- Pull request MCP SDK #2930: expectedResource для requireBearerAuth
- Примечания к выпуску MCP TypeScript SDK 1.32.0
- MITRE CWE-863: некорректная авторизация
- 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