Уязвимость в просмотрщике блокнотов GitHub Enterprise Server позволяет извлечь секреты установки, а затем выполнить на ней произвольный код. Исправление вошло в версию 3.22.1. GitHub присвоил проблеме идентификатор CVE-2026-77987 и относит её к критическим. Эксплуатация не требует учётной записи, если в организации выключен режим приватности. Когда такой режим включён, достаточно прав любого аутентифицированного пользователя.
Детали уязвимостей
Механика выглядит необычно. Злоумышленник с сетевым доступом к серверу отправляет ссылку на просмотр блокнота, в которой явно указан порт. Тем самым запрос уходит не к самому просмотрщику, а к внутренним службам, работающим на том же устройстве. Напрямую данные не возвращаются, поэтому сначала утечки как таковой нет. Время ответа зависит от того, угадал ли атакующий нужное значение. Медленный ответ означает одно, быстрый - другое. Такой побочный канал называют оракулом: он не отдаёт содержимое, но подтверждает догадки. Шаг за шагом перебор сужает пространство поиска, и из установки извлекаются секреты. Часть из них даёт возможность запустить собственный код на сервере.
Просмотрщик блокнотов нужен для файлов с кодом, расчётами и пояснениями, которые сотрудники хранят прямо в репозиториях. Это удобная функция, и запросы к ней не выглядят подозрительно для систем обнаружения. Они идут на легитимный сервис через обычный сетевой доступ. Поэтому защита встроенными средствами наблюдения здесь почти не помогает. Атакующий не оставляет записей о том, что именно он проверял, ведь каждая попытка похожа на штатное обращение к странице.
Важны и условия эксплуатации. Выключенный режим приватности означает, что посмотреть содержимое установки может любой, кто дотянулся до неё по сети. Включённый режим поднимает планку, но невысоко: подойдёт учётная запись рядового сотрудника, у которого есть доступ к серверу. Такой пользователь часто есть у подрядчиков и у сотрудников смежных подразделений. Значит, внутренний нарушитель или владелец украденного пароля получает тот же инструмент, что и внешний атакующий.
Это важно по двум причинам. GitHub Enterprise Server ставят на собственное оборудование, в том числе в закрытых контурах. Владелец такой установки сам отвечает за своевременную установку исправлений. Плюс задержка между публикацией сведений и обновлением часто измеряется неделями. За это время внутренний узел успевает стать точкой входа в корпоративную сеть. Извлечённые секреты дают злоумышленнику возможность закрепиться на устройстве и действовать от имени служб.
Второй уязвимости в 3.22.1 присвоен идентификатор CVE-2026-77912, её тяжесть GitHub оценивает как высокую. Аутентифицированный пользователь публикует специально подготовленный текст в формате Markdown, например комментарий к задаче. Конвейер обработки разметки переписывал кавычки в уже очищенном фрагменте и не проводил повторную проверку. Из-за этого в готовую страницу попадали произвольные атрибуты HTML. Когда другой пользователь открывал комментарий, в его браузере выполнялся чужой скрипт. Межсайтовый скриптинг такого рода даёт доступ к данным, которые видит жертва. Атакующий может менять состояние системы от её имени и выводить информацию наружу. Права на запись у жертвы позволяют разослать полезную нагрузку дальше.
Обе проблемы нашли участники программы вознаграждения за находки в области безопасности. О фактах эксплуатации в реальных атаках GitHub не сообщает. Отсутствие таких сведений не отменяет риска: публичное описание уже появилось, а локальные установки обновляют медленнее облачных сервисов.
GitHub закрыл в том же выпуске ещё две проблемы безопасности. Отчёты, доступные по внутреннему пути /stafftools/reports/, открывались с помощью устаревшего бессрочного токена. Администраторам, которые забирали данные программно, придётся перейти на персональный токен доступа (классический) с областью site_admin. Вторая касается реестра пакетов GitHub Packages. Реестр не проверял права пользователя перед продолжением или завершением загрузки. Злоумышленник, узнав идентификаторы чужой загрузки, мог испортить пакет. Теперь проверка авторизации проходит до любых изменений.
Обновление 3.22.1 вышло 22 сентября 2026 года. Администраторам стоит установить его на все узлы, включая кластеры и реплики. После обновления просмотрщик блокнотов отклоняет ссылки с явно указанным портом. В выпуске есть и другие изменения. Появились настройки для ограничения размера временных таблиц MySQL, а также отдельная квота на процессорное время для резервного копирования баз данных. Параметры app.github.topic-checker-connect-timeout-sec и app.github.topic-checker-socket-timeout-sec увеличили время ожидания при опросе внутренних тем с десяти до тридцати секунд. Для установок с высокой нагрузкой на запись исправили рост потребления памяти Redis: раньше служба создавала периодические снимки в дополнение к настроенному журналу. Несколько исправлений касаются резервного копирования и восстановления. В частности, восстановление больше не считается успешным, если копирование репозиториев и файлов-сниппетов сорвалось. Служба резервного копирования теперь сообщает об ошибке корректно.
Есть и предупреждение. При обновлении удаляются настраиваемые правила межсетевого экрана. Если администратор задавал их вручную, после установки версии 3.22.1 придётся применить правила заново. Плюс при первой проверке после обновления или перезапуска сканирование секретов может занять на несколько секунд больше времени: базы для поиска закономерностей собираются на самой установке. Пользователям с ограниченным списком разрешённых действий стоит продумать окно обслуживания заранее.
Обе уязвимости показывают, где чаще ошибаются разработчики сложных платформ. Проверка входных данных должна охватывать не только первый запрос, но и все последующие преобразования. Обработка разметки меняет текст уже после очистки, поэтому защита, выставленная однажды, перестаёт работать. Оракулы по времени обходят фильтры, которые следят за содержимым ответов. Для закрытых установок цена такой ошибки выше: злоумышленнику не нужен доступ к облаку, достаточно одного сетевого подключения к серверу. Быстрое обновление до 3.22.1 закрывает оба вектора.
Ссылки
- https://docs.github.com/en/enterprise-server@3.22/admin/release-notes
- https://www.cve.org/cverecord?id=CVE-2026-77912
- https://www.cve.org/cverecord?id=CVE-2026-77987