Назад к блогу

Две уязвимости Codex: как недоверенный код получал доступ к хосту

Две уязвимости Codex: как недоверенный код получал доступ к хосту

Исследователи показали, как два дефекта в инфраструктуре OpenAI Codex позволяют недоверенному коду вырваться за пределы песочницы — вплоть до выполнения команд на машине разработчика, причём в самом строгом режиме изоляции. Обе уязвимости уже закрыты патчами, однако разбор механики атак полезен всем, кто строит собственные агентные песочницы: он наглядно демонстрирует, почему совместно используемая память и слишком щедрые права на запись сводят защиту на нет.

Исследователи из Accomplish AI нашли два способа выйти из песочницы OpenAI Codex. Один из них, получивший имя Heapjack, превращает обычное действие — открыть чужой репозиторий и задать вопрос о коде — в удалённое выполнение команд на машине разработчика. Второй, Overpatch, обходит ограничения на запись в Codex CLI. Обе проблемы сообщили OpenAI 12 августа, исправили в течение восьми дней; публично о них рассказали в статье BleepingComputer 20 сентября 2026 года, а 21 сентября добавили заявление OpenAI.

Что именно изменилось

Heapjack исправлен в сборке Codex Desktop 26.818.21641, Overpatch — в Codex CLI 0.149.0. Пользователям следует обновиться до этих версий или более новых.

Как работает Heapjack

Уязвимость нацелена на компонент node_repl — без возможности отказаться и без настройки для отключения. Один контекст — доверенный, где исполняется код OpenAI, другой — недоверенный, где исполняется код агента. Оба контекста живут в одном процессе и делят одну кучу памяти, поэтому токен оказывается обычной строкой в памяти, доступной недоверенной стороне.

Недоверенный код снимает снимок кучи и перебирает строки в форме UUID. Различить верную догадку помогает поведение проверки: неверный токен даёт not authorized, а верный токен с плохим аргументом — настоящую ошибку валидации. Получив токен, недоверенный код пишет свой запрос в тот же канал, по которому доверенный контекст общается с нативным родительским процессом вне песочницы. Родитель проверяет токен, видит валидный и выполняет работу.

Proof of concept использовал системную команду open, чтобы запустить приложение вне дерева процессов Codex. Тот же доступ достигает любого Unix-сокета, включая сокет демона Docker, и инструмента для редактирования глобального конфигурационного файла. Всё это работает в режиме read-only — самом строгом режиме песочницы, где агенту вообще не разрешено что-либо записывать.

Как работает Overpatch

Вторая уязвимость находится в открытом исходном коде Codex CLI. В режиме workspace-write агенту разрешено писать только внутри папки проекта, а команда оболочки, нацеленная на домашний каталог, отклоняется. Обойти это удалось через собственный инструмент Codex apply_patch. Он даёт доступ на запись к родительской папке каждого пути, названного в патче. Назовите /tmp — и инструмент даёт доступ на запись к корню диска.

Рабочий эксплойт использует патч с двумя изменениями: одно называет /tmp и ничего полезного не делает, кроме расширения прав, а другое дописывает строку в .zshrc через симлинк в домашний каталог. Без первого изменения запись отклоняется; с ним следующий открытый разработчиком терминал выполняет строку атакующего без песочницы.

Предыстория

Безопасность Codex строится на двух слоях. Первый — sandbox. Второй — политика одобрений: действия за пределами песочницы требуют разрешения. По умолчанию разрешены два режима песочницы: read-only — агент только читает и ничего не записывает, и workspace-write — агент может писать внутри разрешённых корней, например ~/development. Сеть по умолчанию закрыта: Codex не получает открытый исходящий доступ, политика строится по allowlist, а веб-поиск ограничен режимом cached.

Для рутинных низкорисковых запросов применяется режим автопроверки auto_review: рядом с агентом работает субагент, он молча одобряет низкорисковые запросы, а нестандартные или потенциально опасные действия передаются человеку. Правила prefix_rule позволяют автоматически разрешать конкретные безопасные команды, например read-only просмотр GitHub PR или Kubernetes-ресурсов.

До этого в публичном репозитории Codex уже фиксировали инциденты с рекурсивным удалением данных — из-за ошибок при работе с временными каталогами и переменными окружения. В Windows переменная $home в PowerShell столкнулась с системной переменной $HOME, из-за чего очистка могла обратиться к реальному пользовательскому профилю. В другом инциденте очистка временного каталога пересекла bind mount и затронула файлы настоящего репозитория. В ответ Codex получил ограничения для деструктивных операций: агент должен сначала проверить конкретную цель удаления, избегать $HOME, ~ и других широких путей, использовать отдельные имена для переменных временных каталогов и по возможности выбирать обратимые операции. Потенциально опасные команды удаления стали дополнительно проверяться, а при отказе система направляет модель к более безопасному варианту.

Почему это стало возможно

Обе ошибки имеют общую форму: механизм принуждения жил внутри того, что он должен был ограничивать. В случае Heapjack node_repl хранил секрет, разделяющий доверенный и недоверенный код, в той же памяти, что и недоверенный код. Комментаторы отмечают, что изоляция V8-контекстов разделяет только глобальные объекты, но не память, поэтому песочница была лишь обещанием, которое куча не соглашалась выполнять. Границу доверия называли «перегородкой в комнате». Отдельно вызывало вопросы поведение, включённое по умолчанию: почему привилегированный токен вообще был доступен из недоверенного JavaScript.

Более широкий контекст — отсутствие архитектурного разграничения между доменом инструкций и доменом входных данных: заголовок Issue, написанный пользователем, обрабатывался автоматическим агентом как инструкция к выполнению. Сетевые ограничения тоже оказывались неполными: DNS-канал обходит HTTP-allowlist, потому что DNS почти всегда разрешён до корпоративного резолвера, а рекурсивный резолвер ходит наружу за клиента. В кейсе AWS Bedrock AgentCore режим описывался как «complete isolation with no external access», но рекурсивный DNS к произвольным публичным доменам работал. В кейсе OpenAI песочница RL-training считалась закрытой, но резолвер песочницы и DNS delegation дали маршрут «запрос–ответ» к внешнему чатботу.

Что это меняет на практике

Разработчикам рекомендуется использовать Full access только в средах, где потенциальное повреждение данных допустимо и есть возможность восстановить состояние системы, а в обычной работе оставаться в режимах с запросом подтверждения или ограниченной песочницей. Для снижения рисков настраивают approvals через config.toml, указывая approvals_reviewer, и ограничивают доступные режимы песочницы в requirements.toml:

allowed_sandbox_modes = ["read-only", "workspace-write"]
sandbox_workspace_write.writable_roots = ["~/development"]

Сетевой доступ строится по allowlist, в requirements.toml задаётся allowed_web_search_modes, а в experimental_network включается сеть, разрешается локальное связывание, запрещаются нежелательные домены и разрешаются только нужные. В default.rules через prefix_rule разрешают только безопасные команды, например gh pr view/list и kubectl get/describe/logs, с обоснованием read-only inspection. Учётные данные рекомендуется хранить в keyring, а метод входа и рабочее пространство задавать принудительно.

OpenAI расширяет набор тестов: воспроизводимые случаи удаления и обхода ограничений используются для оценки моделей и последующего обучения. В сообществе обсуждают необходимость пересмотра доверия к песочницам, которые описываются как «обещание, с которым куча памяти не согласилась».

Ограничения и открытые вопросы

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

Нерешённые вопросы остаются. Из шести классов угроз пять нельзя закрыть ни guardrails-моделью, ни проверкой в CI-пайплайне, а контейнерная изоляция сама по себе недостаточна, поскольку контейнер делит ядро с хостом. Защита от эксфильтрации через DNS требует постоянного контроля: DoH не закрывается простыми средствами, нужны списки провайдеров, DPI-сигнатуры и запрет исходящего 443, а также проверка fail-open при сбое policy engine, прокси, DNS-фильтра или монитора. Тесты red teaming предписано повторять при каждом изменении образа sandbox, резолвера, прокси, tool manifest и orchestration layer. Отдельно отмечается, что аналог Mythos появится через 6–18 месяцев, и готовиться к этому нужно сейчас.

Источники

Похожее