DeepSeek Harness позволяла злоумышленнику в песочнице выполнять произвольные команды, просто изменив HTTP-заголовок Host на 127.0.0.1, что соответствует оценке 9.4 по шкале CVSS. Эта уязвимость демонстрирует, как одно неверное решение о доверии может превратить защитный барьер в открытый бэкдор.

Как просочилась ошибка

Уязвимый код находится в одной функции, которая считывает заголовок Host запроса и, если его значение совпадает с loopback-адресом, обрабатывает запрос как пришедший с локальной машины.

Злоумышленнику, способному выполнять код внутри песочницы, не нужна сложная полезная нагрузка. Отправив всего один HTTP-запрос с Host: 127.0.0.1, он заставляет бэкенд поверить, что вызов исходит от самого хоста, что позволяет пропустить все запросы безопасности, проверки ограничений скорости (rate-limit) и этапы валидации команд. Результат: неограниченное выполнение команд без необходимости дальнейшего взаимодействия.

Почему доверять заголовкам опасно

Заголовки — это текстовые строки, предоставляемые вызывающей стороной. Независимо от того, называется ли поле Host, X-Forwarded-For или любым другим именем, клиент может установить в нем любое значение. Единственным надежным источником истины о том, откуда на самом деле пришло соединение, является транспортный уровень — IP-адрес источника сокета, который операционная система фиксирует по завершении TCP-рукопожатия.

Когда приложение решает доверять заголовку, не подтвердив, что его добавил известный и правильно настроенный прокси-сервер, оно фактически вручает злоумышленнику ключи от королевства. Ошибка в DeepSeek Harness — классический пример такого просчета.

Реальное влияние: пример shell.online

Open-source проект shell.online, предлагающий веб-терминал, недавно задокументировал ту же ловушку. Он использует флаг конфигурации под названием TRUST_PROXY:

  • TRUST_PROXY = 0 — приложение игнорирует заголовок X-Forwarded-For и полагается на удаленный адрес сокета. Это не позволяет клиенту подделать IP-адрес для обхода ограничений скорости или маскировки под доверенного пользователя.
  • TRUST_PROXY = 1 — приложение доверяет заголовку X-Forwarded-For как идентификатору клиента. Если сервис не находится за реальным прокси-сервером, который очищает этот заголовок, злоумышленник может указывать новый IP-адрес в каждом запросе, фактически сбрасывая любые ограничения (throttling) для конкретного IP.

Ошибка в DeepSeek повторяет этот сценарий: код доверял заголовку Host, как если бы его установил прокси-сервер, хотя к сервису можно было обратиться напрямую.

Что делать разработчикам прямо сейчас

  1. Проведите аудит всех мест, где вы считываете заголовки, предоставляемые клиентом. Определите, какие заголовки вы считаете авторитетными (например, Host, X-Forwarded-For, X-Real-IP), и убедитесь, что доверенный прокси-сервер гарантированно перезаписывает их до того, как они попадут в ваше приложение.
  2. Привязывайте решения безопасности к адресу сокета, когда это возможно. Используйте IP-адрес источника, предоставляемый ОС, для аутентификации, ограничения скорости и проверок контроля доступа.
  3. Включайте флаги доверия прокси только в том случае, если перед сервисом стоит правильно настроенный обратный прокси-сервер. Если вы запускаете приложение напрямую, держите эти флаги отключенными.
  4. Документируйте необходимую топологию развертывания в README или руководстве по развертыванию вашего проекта, чтобы пользователи, использующие self-hosting, знали о необходимости наличия прокси.
  5. Используйте инструменты статического анализа или инструменты проверки кода, которые помечают прямое использование заголовков для принятия решений безопасности без сопутствующей логики валидации прокси.

На что обратить внимание в дальнейшем

Сообщества, выпускающие self-hosted веб-сервисы, скорее всего, пересмотрят свои настройки доверия прокси после этого инцидента.

Главный урок суров: никогда не позволяйте тексту, который может написать кто угодно в интернете, диктовать состояние безопасности вашей системы. Доверяйте сетевому уровню, а не уровню запроса.