GitHub: один git push с лишним символом давал RCE — что было в CVE-2026-3854
Любой с push-доступом мог выполнить команды на серверах GitHub. github.com и Cloud закрыли в день репорта 4 марта, для GHES патч — теперь публично. Разбираем атаку.
Новости TprogerЕсли у вас аккаунт на github.com — за вас уже всё пропатчили: GitHub закрыл уязвимость 4 марта, через час с небольшим после получения репорта от Wiz, и форензика по логам никаких следов эксплуатации не нашла. Если вы админ GitHub Enterprise Server — обновляйтесь сейчас, патчи опубликованы 28 апреля. Любой git push с точкой с запятой в push-опциях давал атакующему shell на сервере, обрабатывающем этот пуш — официальный пост в GitHub Blog.
CVE-2026-3854 — RCE-уязвимость в обработке push-опций git, CVSS 8.7. Нашли её исследователи Wiz, отправили в bug bounty программу 4 марта 2026 года. GitHub воспроизвёл уязвимость за 40 минут, выкатил фикс на github.com ещё через 35 — итого «менее чем за два часа», как сами они округлили. Bounty payout — один из крупнейших в истории GitHub Bug Bounty; публично программа платит от $30 000 за критические RCE-находки.
Под удар попали все варианты GitHub: github.com, GitHub Enterprise Cloud (включая Data Residency — изолированные облачные инстансы для регулируемых отраслей — и Enterprise Managed Users — корпоративный SSO-tenant), и GitHub Enterprise Server (GHES, самохостинг). Клиентам Cloud делать ничего не нужно — там пропатчили в день репорта. Админам GHES — обновиться до последнего патча в вашей мажорной ветке и пройтись по аудит-логам.
Ключевые выводы
CVE-2026-3854 (CVSS 8.7) — RCE через push-опции git. Любой пользователь с push-доступом к репозиторию мог выполнить команды на сервере, обрабатывающем его пуш. Один git push --push-option=... и сервер выполнял чужой код.
Нашёл Wiz, репорт через bug bounty 4 марта 2026 года. github.com закрыли в тот же день, через 1 час 15 минут после получения. Форензика следов эксплуатации не нашла — все срабатывания уязвимого кодового пути в логах сошлись на тестах самих Wiz.
Затронуты: github.com, GitHub Enterprise Cloud (плюс Data Residency и Enterprise Managed Users), GitHub Enterprise Server. Cloud-варианты пропатчены 4 марта, GHES — теперь публично.
Для GHES — обновляться сейчас. Патчи: 3.14.25 / 3.15.20 / 3.16.16 / 3.17.13 / 3.18.7 / 3.19.4 / 3.20.0 и новее. Эксплуатация требует пользователя с push-доступом, но на корпоративном инстансе это часто весь штат разработчиков.
Bounty payout — один из самых больших в истории GitHub Bug Bounty, по словам самих GitHub. Точную сумму не назвали, но программа публично платит от $30 000 за критические RCE-находки и допускает доплаты сверху за исключительные репорты.
Что такое push-опции и зачем они нужны
git push --push-option=foo=bar — это легитимная фича git: при пуше клиент передаёт серверу произвольные пары ключ-значение. На сервере хуки видят их через переменные окружения GIT_PUSH_OPTION_* и могут использовать для сигналов вроде «обойти проверку pre-receive в этот раз», «уведомить вот такой пайплайн в CI», «явно пометить пуш как hotfix». Сама фича в git с сентября 2016 года (релиз 2.10), включить можно флагом, конфигом push.pushOption или git-алиасом.
Внутри GitHub push-опции едут через служебный межсервисный протокол: метаданные о пуше — тип репозитория, кто пушит, в какое окружение его обработать — складываются в служебную строку и передаются между микросервисами. Именно в этой строке и обнаружилась дыра.
Что было в инъекции
Разделителем полей во внутреннем протоколе была точка с запятой ;. GitHub в техническом разделе своего блога её прямо не называет, но в рекомендациях для админов GHES просит искать ; в /var/log/github-audit.log — оттуда видно, какой именно символ был делимитером. Та же точка с запятой могла оказаться в значении push-опции, переданной пользователем, из-за чего и появлялась инъекция.
Дальше — классическая инъекция, как SQL-injection, только не в базу, а в служебный протокол между микросервисами GitHub. Пользователь подсовывает push-опцию вида foo=bar;trustedField=..., сервер бережно складывает её в строку метаданных, downstream-сервис парсит строку, видит «лишнее» поле и интерпретирует его как доверенное внутреннее значение. Сцепив несколько таких полей подряд, исследователи добились трёх вещей: переопределили окружение, в котором обрабатывался пуш; обошли sandbox, который обычно ограничивает выполнение хуков; и выполнили произвольные команды на сервере.
Самое неприятное — для атаки не нужен был никакой доступ к чужим репозиториям. Достаточно собственного приватного репозитория, который можно создать за 5 секунд и закрыть от всех остальных. С push-доступом к этому репозиторию атакующий получал shell на инфраструктуре, обрабатывающей пуш — на github.com это shared-инфраструктура, через которую идут пуши всех пользователей.
Хронология: 55 дней приватного фикса
- 4 марта 2026, 17:45 UTC — Wiz отправляют репорт в bug bounty.
- 4 марта 2026, 18:25 UTC — GitHub воспроизводит уязвимость внутри (через 40 минут).
- 4 марта 2026, 19:00 UTC — фикс выкачен на github.com (через 1 час 15 минут после репорта).
- 4 марта — параллельно закрыто на GitHub Enterprise Cloud (все варианты).
- Март-апрель — приватная работа над GHES патчами + форензика по логам.
- 28 апреля 2026 — публичный пост, релизы GHES, выдан CVE-2026-3854.
Полтора месяца молчания — потому что у GHES медленный цикл релизов и нужно было параллельно подготовить патчи для всех поддерживаемых мажорных веток. Параллельно GitHub перерыл логи: уязвимый кодовый путь в нормальной работе не дёргается совсем, поэтому любое его срабатывание в телеметрии — кандидат на exploit. Все обнаруженные срабатывания сошлись на тестовой активности самих Wiz, других следов не нашли.
Сама архитектура атаки им в этом помогла. Эксплойт заставляет сервер пройти по кодовому пути, который никогда не используется в нормальной работе github.com — это прямое следствие того, как именно работает инъекция. Атакующий не может «спрятаться» в обычном трафике: каждое его срабатывание остаётся в телеметрии как явная аномалия.
Кого затронуло
Под уязвимость попали все площадки GitHub:
- github.com (публичная площадка) — пропатчена 4 марта 2026.
- GitHub Enterprise Cloud — пропатчен 4 марта.
- GitHub Enterprise Cloud with Data Residency — пропатчен 4 марта.
- GitHub Enterprise Cloud with Enterprise Managed Users — пропатчен 4 марта.
- GitHub Enterprise Server (GHES, self-hosted) — патчи 28 апреля 2026.
Эксплуатация на GHES требует аутентифицированного пользователя с push-доступом на конкретный инстанс. На корпоративных серверах это, как правило, весь штат разработчиков и любой внешний контрактник, которого пустили в проект. То есть для большинства компаний это эквивалент «локальный пользователь → root на сервере GitHub».
Что делать админам GHES
Обновитесь до одного из следующих релизов в вашей мажорной ветке (или новее):
- GitHub Enterprise Server 3.14.25
- GitHub Enterprise Server 3.15.20
- GitHub Enterprise Server 3.16.16
- GitHub Enterprise Server 3.17.13
- GitHub Enterprise Server 3.18.7
- GitHub Enterprise Server 3.19.4
- GitHub Enterprise Server 3.20.0 или позже
После обновления — пройдитесь по /var/log/github-audit.log и поищите push-операции, в push-опциях которых встречается символ ;. GitHub рекомендует это сделать «из соображений предосторожности» — exploitation на github.com они не нашли, но GHES — это ваш инстанс, и логи только у вас. Команда на коленке:
Если что-то нашли — копайте дальше: смотрите учётку, время, репозиторий, уходите в конкретные хуки и их вывод. Если ничего нет — фиксируйте патч-уровень и продолжайте жить, в Cloud-вариантах эта же история обошлась без жертв.
Defense in depth: как туда попал лишний код-путь
GitHub в том же посте признаются в дополнительной находке. Уязвимый кодовый путь не должен был быть доступен в той среде, в которой он отрабатывал. Раньше деплой явно его исключал — путь нужен был только для другой конфигурации продукта. Когда модель деплоя поменяли, исключение не перенесли, и код-путь начал лежать на диске рядом с продакшен-обработчиком пушей.
Это не первичный баг — без injection до этого кода всё равно было не дотянуться. Но это второй слой обороны, которого здесь не оказалось. GitHub отдельно зачистил окружения от лишнего, и теперь даже при гипотетической второй injection через push-опции там просто нечего эксплуатировать.
Урок: при смене модели деплоя пересматривайте список того, что в этой модели не должно быть доступно. Каждый кодовый путь — отдельный кусок атак-поверхности, и держать его «на всякий случай» обходится дороже, чем удалить.
Часто задаваемые вопросы
Затронуло ли меня, если я обычный пользователь github.com?
Нет. github.com закрыт ещё 4 марта 2026, через 2 часа после получения репорта. Форензика по логам показала, что никто, кроме исследователей Wiz, к уязвимому коду не подходил. Никаких действий от пользователей не требуется.
А что насчёт push-опций — нужно ли мне их теперь бояться?
Push-опции как фича git никуда не делись — они полезные. Уязвимость была в обработке значений на сервере, не в самой клиентской команде. Можно спокойно использовать git push --push-option=... и в локальной работе, и в CI. У GitLab, Gerrit и self-hosted git-серверов — своя реализация и свои потенциальные баги, но к этому конкретному CVE-2026-3854 они отношения не имеют.
Можно ли понять, эксплуатировали ли мою GHES-инстанцию?
Да, частично. Уязвимый кодовый путь в нормальной работе не используется, поэтому любая его активация в логах — индикатор. Ищите в /var/log/github-audit.log push-операции, в push-опциях которых встречается ;. Если такие есть — анализируйте учётку, репозиторий и хуки, которые отработали на этом пуше.
Сколько GitHub заплатил Wiz за репорт?
Точную сумму GitHub не раскрыли. По их собственным словам, payout будет «одним из крупнейших в истории нашей программы Bug Bounty». Программа публично платит от $30 000 за критические находки и допускает дополнительные премии — реальный размер для одной из самых дорогих находок в истории логично ждать значительно выше базовой ставки.
Wiz — это что за исследователи?
Cloud security вендор, известный громкими находками в Microsoft Azure, AWS и не только. Регулярно делают глубокие архитектурные обзоры публичных облаков, в этот раз — GitHub. Технический разбор уже опубликован в их блоге одновременно с public disclosure 28 апреля: Wiz blog.
Выводы
CVE-2026-3854 — учебный пример инъекции через делимитер во внутреннем протоколе. Ничего экзотического: пользовательский ввод попал в служебную строку, разделитель совпал, downstream-парсер посчитал «лишнее» доверенным. То, что такая дыра прожила какое-то время в одном из самых внимательных к безопасности продуктов индустрии, — отдельная иллюстрация, насколько живучи такие классы багов даже у зрелых команд.
40 минут на репродукцию и 1 час 15 минут на патч в продакшен — впечатляющие цифры incident response. GitHub отрабатывает такие кейсы постоянно, но всё равно показательно: расследование, фикс, прогон через CI и выкат на github.com уместились в один кофе-брейк команды.
Источники: официальный пост в GitHub Blog, advisory CVE-2026-3854, технический разбор Wiz. Если у вас GHES — обновитесь, проверьте логи, идите дальше. Если только аккаунт на github.com — благодарите security-команду GitHub: вы узнали об этой истории, когда её уже не было.