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, как если бы его установил прокси-сервер, хотя к сервису можно было обратиться напрямую.
Что делать разработчикам прямо сейчас
- Проведите аудит всех мест, где вы считываете заголовки, предоставляемые клиентом. Определите, какие заголовки вы считаете авторитетными (например, Host, X-Forwarded-For, X-Real-IP), и убедитесь, что доверенный прокси-сервер гарантированно перезаписывает их до того, как они попадут в ваше приложение.
- Привязывайте решения безопасности к адресу сокета, когда это возможно. Используйте IP-адрес источника, предоставляемый ОС, для аутентификации, ограничения скорости и проверок контроля доступа.
- Включайте флаги доверия прокси только в том случае, если перед сервисом стоит правильно настроенный обратный прокси-сервер. Если вы запускаете приложение напрямую, держите эти флаги отключенными.
- Документируйте необходимую топологию развертывания в README или руководстве по развертыванию вашего проекта, чтобы пользователи, использующие self-hosting, знали о необходимости наличия прокси.
- Используйте инструменты статического анализа или инструменты проверки кода, которые помечают прямое использование заголовков для принятия решений безопасности без сопутствующей логики валидации прокси.
На что обратить внимание в дальнейшем
Сообщества, выпускающие self-hosted веб-сервисы, скорее всего, пересмотрят свои настройки доверия прокси после этого инцидента.
Главный урок суров: никогда не позволяйте тексту, который может написать кто угодно в интернете, диктовать состояние безопасности вашей системы. Доверяйте сетевому уровню, а не уровню запроса.
