Уязвимость в официальном Python SDK для Model Context Protocol позволяла вредоносному MCP-серверу перенаправить OAuth-данные клиента на подконтрольный атакующему адрес. Разработчики SDK подтвердили проблему в бюллетене безопасности. Под угрозой находились секрет OAuth-клиента, код авторизации и проверочный ключ PKCE. Исправления выпущены в версиях 1.30.0 для ветки 1.x и 2.2.0 для ветки 2.x.

MCP, или Model Context Protocol, представляет собой открытый стандарт для подключения ИИ-приложений к внешним инструментам и данным. Уязвимый пакет используют при создании MCP-серверов и клиентов, однако сама проблема затрагивает именно клиентскую часть. Во время обычной авторизации MCP-клиент спрашивает у сервера, где расположен нужный сервер авторизации, после чего проводит через него OAuth-обмен.
В версиях с ошибкой ответ MCP-сервера проверялся не всегда. Злоумышленник мог прямо объявить собственный узел сервером авторизации либо передать метаданные с адресом настоящего сервиса, но указать другой endpoint для отправки учетных данных. Во втором случае конфигурация выглядела убедительнее: пользователь видел знакомый сервис, а секреты уходили на чужой сервер.
Перехватив секрет клиента, код авторизации и проверочный ключ PKCE, атакующий мог обратиться уже к настоящему сервису входа и получить действующий access token. Компания Cycode, сообщившая об уязвимости, воспроизвела весь обмен в тесте. Полученный токен имел те разрешения, которые ранее были выданы пострадавшему приложению. Клиентский секрет остается рабочим до смены или ротации, поэтому последствия не ограничиваются одной попыткой входа.
PKCE обычно мешает использовать похищенный код авторизации: для обмена нужен одноразовый проверочный ключ, известный исходному клиенту. Здесь оба значения попадали к одному атакующему, и защитный смысл PKCE исчезал. При интерактивной авторизации человек по-прежнему должен был начать или одобрить вход, причем, по данным Cycode, страница входа была настоящей. Пользователь не видел явных признаков подмены. Для такого сценария тяжесть оценили в 6,5 балла.
Для провайдеров ClientCredentialsOAuthProvider и PrivateKeyJWTOAuthProvider участие человека не требуется: нет ни пользовательского входа, ни ручного подтверждения. Поэтому уязвимость для них получила оценку High, 7,5 балла. На 29 сентября CVE еще не был присвоен; год этой даты в опубликованных сведениях не указан.
Риску подвержено приложение, которое использует официальный MCP Python SDK как MCP-клиент, соединяется по HTTP, хранит данные доступа к легитимному сервису авторизации и может обращаться к недоверенному либо не полностью контролируемому MCP-серверу. Уязвимые провайдеры: OAuthClientProvider, ClientCredentialsOAuthProvider, PrivateKeyJWTOAuthProvider и устаревший RFC7523OAuthClientProvider из ветки 1.x. Не затронуты MCP-серверы, созданные с помощью SDK, локальные клиенты на stdio и клиенты, самостоятельно прикрепляющие или передающие готовые токены.
В ветке 1.x уязвимы версии с 1.9.1 по 1.29.1 включительно, исправление находится в 1.30.0. В ветке 2.x проблема присутствует с 2.0.0 по 2.1.1, безопасная версия начинается с 2.2.0. Обновленный клиент заранее определяет ожидаемый сервер авторизации, а затем отклоняет метаданные или конфигурацию, указывающие на другой сервис.
Для ClientCredentialsOAuthProvider и PrivateKeyJWTOAuthProvider одного обновления мало. В бюллетене это сформулировано прямо: «обновление ничего не меняет, пока вы также не передадите issuer=». Параметр issuer= должен указывать сервис авторизации, которому принадлежат учетные данные. В версии 1.30.0 сообщение об отсутствующем issuer= оформлено как обычное предупреждение об устаревании, а Python по умолчанию скрывает такие предупреждения. Его легко не заметить. У RFC7523OAuthClientProvider параметра issuer= нет, поэтому пользователям следует перейти на ClientCredentialsOAuthProvider или PrivateKeyJWTOAuthProvider.
После установки исправления необходимо один раз удалить сохраненные регистрации OAuth-клиентов. Записи, созданные старыми версиями SDK, не привязаны к конкретному серверу авторизации, и обновление не добавляет эту привязку задним числом. Если клиент уже мог подключаться к недоверенному MCP-серверу, его OAuth-секрет следует сменить, а действующие токены отозвать на настоящем сервере входа. Для старых версий SDK обходного решения нет: допустимы соединения только с полностью доверенными MCP-серверами.
Проверки issuer появились в примечаниях к выпускам 1.30.0 и 2.2.0, опубликованных 7 сентября; год публикации в имеющихся данных не назван. Изменения поместили в раздел об изменении поведения, не обозначив их как исправление безопасности. В бюллетене указаны восемь исследователей, сообщивших о проблеме, включая специалиста Cycode, но его имя не раскрыто. Ни официальный бюллетень, ни отчет Cycode не содержали сведений о реальных атаках; на описанный момент сообщений об эксплуатации из других источников также не было.

Изображение носит иллюстративный характер
MCP, или Model Context Protocol, представляет собой открытый стандарт для подключения ИИ-приложений к внешним инструментам и данным. Уязвимый пакет используют при создании MCP-серверов и клиентов, однако сама проблема затрагивает именно клиентскую часть. Во время обычной авторизации MCP-клиент спрашивает у сервера, где расположен нужный сервер авторизации, после чего проводит через него OAuth-обмен.
В версиях с ошибкой ответ MCP-сервера проверялся не всегда. Злоумышленник мог прямо объявить собственный узел сервером авторизации либо передать метаданные с адресом настоящего сервиса, но указать другой endpoint для отправки учетных данных. Во втором случае конфигурация выглядела убедительнее: пользователь видел знакомый сервис, а секреты уходили на чужой сервер.
Перехватив секрет клиента, код авторизации и проверочный ключ PKCE, атакующий мог обратиться уже к настоящему сервису входа и получить действующий access token. Компания Cycode, сообщившая об уязвимости, воспроизвела весь обмен в тесте. Полученный токен имел те разрешения, которые ранее были выданы пострадавшему приложению. Клиентский секрет остается рабочим до смены или ротации, поэтому последствия не ограничиваются одной попыткой входа.
PKCE обычно мешает использовать похищенный код авторизации: для обмена нужен одноразовый проверочный ключ, известный исходному клиенту. Здесь оба значения попадали к одному атакующему, и защитный смысл PKCE исчезал. При интерактивной авторизации человек по-прежнему должен был начать или одобрить вход, причем, по данным Cycode, страница входа была настоящей. Пользователь не видел явных признаков подмены. Для такого сценария тяжесть оценили в 6,5 балла.
Для провайдеров ClientCredentialsOAuthProvider и PrivateKeyJWTOAuthProvider участие человека не требуется: нет ни пользовательского входа, ни ручного подтверждения. Поэтому уязвимость для них получила оценку High, 7,5 балла. На 29 сентября CVE еще не был присвоен; год этой даты в опубликованных сведениях не указан.
Риску подвержено приложение, которое использует официальный MCP Python SDK как MCP-клиент, соединяется по HTTP, хранит данные доступа к легитимному сервису авторизации и может обращаться к недоверенному либо не полностью контролируемому MCP-серверу. Уязвимые провайдеры: OAuthClientProvider, ClientCredentialsOAuthProvider, PrivateKeyJWTOAuthProvider и устаревший RFC7523OAuthClientProvider из ветки 1.x. Не затронуты MCP-серверы, созданные с помощью SDK, локальные клиенты на stdio и клиенты, самостоятельно прикрепляющие или передающие готовые токены.
В ветке 1.x уязвимы версии с 1.9.1 по 1.29.1 включительно, исправление находится в 1.30.0. В ветке 2.x проблема присутствует с 2.0.0 по 2.1.1, безопасная версия начинается с 2.2.0. Обновленный клиент заранее определяет ожидаемый сервер авторизации, а затем отклоняет метаданные или конфигурацию, указывающие на другой сервис.
Для ClientCredentialsOAuthProvider и PrivateKeyJWTOAuthProvider одного обновления мало. В бюллетене это сформулировано прямо: «обновление ничего не меняет, пока вы также не передадите issuer=». Параметр issuer= должен указывать сервис авторизации, которому принадлежат учетные данные. В версии 1.30.0 сообщение об отсутствующем issuer= оформлено как обычное предупреждение об устаревании, а Python по умолчанию скрывает такие предупреждения. Его легко не заметить. У RFC7523OAuthClientProvider параметра issuer= нет, поэтому пользователям следует перейти на ClientCredentialsOAuthProvider или PrivateKeyJWTOAuthProvider.
После установки исправления необходимо один раз удалить сохраненные регистрации OAuth-клиентов. Записи, созданные старыми версиями SDK, не привязаны к конкретному серверу авторизации, и обновление не добавляет эту привязку задним числом. Если клиент уже мог подключаться к недоверенному MCP-серверу, его OAuth-секрет следует сменить, а действующие токены отозвать на настоящем сервере входа. Для старых версий SDK обходного решения нет: допустимы соединения только с полностью доверенными MCP-серверами.
Проверки issuer появились в примечаниях к выпускам 1.30.0 и 2.2.0, опубликованных 7 сентября; год публикации в имеющихся данных не назван. Изменения поместили в раздел об изменении поведения, не обозначив их как исправление безопасности. В бюллетене указаны восемь исследователей, сообщивших о проблеме, включая специалиста Cycode, но его имя не раскрыто. Ни официальный бюллетень, ни отчет Cycode не содержали сведений о реальных атаках; на описанный момент сообщений об эксплуатации из других источников также не было.