GPUStack: обход аутентификации CVE-2026-102895 через подделку loopback, уже эксплуатируют

GPUStack закрыла уязвимость CVE-2026-102895, которая позволяет обойти аутентификацию и получить права администратора без учётной записи. Ошибка в том, что платформа доверяет запросам с адресом 127.0.0.1: подделав заголовок X-Gpustack-Real-IP или поставив GPUStack за локальный обратный прокси, атакующий выглядит для неё локальным администратором. Оценка CVSS 3.1 - 9.8, критический уровень. Уязвимы все версии до 2.2.0, исправление вышло в 2.2.0 ещё в конце июня, но CVE присвоили только 4 ноября. Сейчас SANS фиксирует активные попытки эксплуатации.

Что позволяет обход

GPUStack - открытый менеджер кластеров GPU для обслуживания ИИ-моделей и выделения GPU-инстансов. Компании разворачивают его на своих серверах, чтобы управлять моделями, воркерами и доступами к облачным провайдерам. Административный интерфейс такой платформы - лакомая цель: через него можно менять модели и воркеры, а также видеть чужие учётные данные.

Механизм ошибки описан в рекомендации GitHub. Функция get_current_user в gpustack/api/auth.py считает запрос, пришедший с loopback-адреса, встроенным администратором, если параметр force_auth_localhost выключен, а по умолчанию он выключен. При этом источник запроса определяется через client_ip_getter, и тот может сообщить 127.0.0.1 без всяких учётных данных двумя путями.

Первый - обратный прокси на том же хосте. В типовой схеме, где прокси передаёт трафик на 127.0.0.1:<порт>, каждый внешний запрос приходит в GPUStack с TCP-адресом 127.0.0.1. Ветка автоматического админа срабатывает, и ни заголовок, ни пароль не нужны. Второй путь - подделанный заголовок X-Gpustack-Real-IP: 127.0.0.1, который тоже заставляет платформу поверить, что запрос локальный.

Схема «localhost доверенный» встречается очень часто. Администраторы ставят Nginx или другой прокси рядом с приложением, чтобы терминировать TLS, и не задумываются, что для приложения все запросы становятся локальными. В случае GPUStack это не просто лишает журналы реального IP клиента, а полностью отключает проверку входа.

Дальше атакующий получает полный административный доступ: перечисляет и меняет пользователей, модели, воркеры и конфигурацию, выпускает постоянные админские API-ключи со scope "*", читает учётные данные воркеров и секреты облачных провайдеров. Через административную функцию POST /v2/inference-backends/from-yaml это доходит до выполнения кода на воркерах. В рекомендации указано, что эксплуатацию уже наблюдали в реальной среде против установки 2.1.1: атакующий создавал собственные бэкенды с обратными оболочками.

Ошибку классифицировали как CWE-287 (некорректная аутентификация), CWE-290 (обход аутентификации подделкой) и CWE-346 (ошибка проверки origin). Девятого ноября CVE-2026-102895 внесли в каталог известных эксплуатируемых уязвимостей CISA: это подтверждение реальной эксплуатации, а не теоретическая оценка.

Условия эксплуатации

Атака идёт по сети и не требует учётной записи, взаимодействия с пользователем или особых условий. Достаточно доступа к API GPUStack и одного из двух сценариев: либо платформа стоит за обратным прокси на том же хосте, либо ей можно прислать поддельный заголовок X-Gpustack-Real-IP.

Именно поэтому типовое самостоятельное развёртывание попадает в зону риска. Если прокси и GPUStack живут на одной машине и прокси передаёт трафик на 127.0.0.1, любая внешняя попытка выглядит локальной. Второй сценарий зависит от того, как настроен приём заголовков: если клиентские X-Gpustack-Real-IP не отбрасываются на входе, подделка проходит.

Затронутые версии

Уязвимы все версии GPUStack до 2.2.0. Исправление вышло в 2.2.0 в конце июня: путь автоматического администрирования для loopback убрали, а обработку клиентского IP и заголовков пересылки ужесточили. Обновляться нужно до 2.2.0 или новее.

Пока обновление не установлено, в рекомендации предлагают три меры. Включить force_auth_localhost=true, чтобы требовать аутентификацию даже для локальных запросов. Не давать прокси или шлюзу возможность превращать внешний трафик в локальный и вырезать заголовок X-Gpustack-Real-IP на периметре. И держать API вне недоверенных сетей - за VPN или на входе с отдельной аутентификацией.

Что видно в атаках

По данным SANS Internet Storm Center, запросы идут с адреса 144.91.73.103. Они простые: GET / с заголовком X-Gpustack-Real-IP: 127.0.0.1 и стандартным User-Agent. Саму уязвимость SANS называет тривиальной, и это видно по запросам: никакого сложного эксплойта не нужно. Кроме корня, тот же адрес в последние дни искал другие ИИ-ресурсы: /v1/models, /v1beta/models?key=x, /v1/messages и /models.

Это похоже на разведку перед более широким сканированием: атакующий проверяет, где живут ИИ-платформы и какие эндпоинты отвечают. С учётом попадания в каталог эксплуатируемых уязвимостей ожидать роста попыток стоит в ближайшие дни.

Что проверить и сделать

Первым делом - версия GPUStack: если она ниже 2.2.0, обновиться. Затем посмотреть журналы на запросы с X-Gpustack-Real-IP: 127.0.0.1 от внешних адресов и на обращения к /v2/inference-backends/from-yaml. Стоит проверить, не появились ли новые администраторы и API-ключи, которых вы не создавали, и не добавлены ли незнакомые модели или воркеры.

Отдельно проверьте прокси и сетевую схему: не передаёт ли обратный прокси трафик на 127.0.0.1, вырезается ли клиентский X-Gpustack-Real-IP, доступен ли API из интернета. Если есть признаки компрометации, меняйте API-ключи, учётные данные воркеров и секреты облачных провайдеров: при административном доступе они могли утечь.

Порядок действий: инвентаризация установок GPUStack, обновление до 2.2.0 и новее, включение force_auth_localhost и очистка заголовка на периметре, затем проверка журналов, ключей и воркеров. Для публично доступных установок это стоит делать вне очереди: уязвимость простая, эксплуатируется и уже попала в список известных атак.

Ссылки

Комментарии: 0