
Публичный PoC и детектор для CVE-2026-20896 («Gitea Docker: один заголовок — любой пользователь»)
Официальный Docker-образ Gitea (до версии 1.26.2 включительно) поставляется со значением REVERSE_PROXY_TRUSTED_PROXIES = * в конфигурации по умолчанию. Если вы включите вход через обратный прокси, этот wildcard означает, что каждый исходный IP-адрес рассматривается как доверенный прокси, поэтому любой, кто может добраться до порта, может отправить заголовок X-WEBAUTH-USER и войти под кем угодно. Без пароля, без токена.
Я сообщил об этом в Gitea, и это исправлено в 1.26.3 / 1.26.4. Этот репозиторий — мой собственный разбор, рабочий PoC и проверочный скрипт. Он посвящён исправленной, публичной уязвимости.
Gitea поддерживает аутентификацию через обратный прокси: вы размещаете её за прокси, который устанавливает X-WEBAUTH-USER, и Gitea доверяет этому заголовку как имени пользователя. Это нормально, пока только ваш прокси может его устанавливать. Настройка, которая должна это обеспечивать, — REVERSE_PROXY_TRUSTED_PROXIES, список разрешённых IP-адресов. Gitea учитывает заголовок только тогда, когда исходный IP-адрес запроса попадает в этот список.
Безопасный по документации вариант по умолчанию — тот, что в app.example.ini, — это 127.0.0.0/8,::1/128: только loopback, так что из коробки доверяется только локальный прокси. Официальный Docker-образ его не использует. Его шаблон app.ini жёстко прописывает * (docker/root/etc/templates/app.ini:55 и docker/rootless/etc/templates/app.ini:52 для rootless-образа). * соответствует каждому исходному IP-адресу, поэтому проверка списка разрешённых ничего не даёт. Включите вход через обратный прокси — и теперь любой, кто может добраться до порта, может отправить заголовок, а не только ваш прокси. При включённой авторегистрации учётная запись создаётся на месте. Отправьте имя пользователя администратора — и вы администратор.
То есть дело не в коде, а в поставляемом значении по умолчанию, и это характерно только для Docker-образов. Установка из бинарников или собранная вручную, которая следует app.example.ini, сохраняет loopback по умолчанию и не затронута.
Нужны Docker и Python 3 (только стандартная библиотека, устанавливать ничего не нужно).
docker compose up -d # boots vulnerable gitea/gitea:1.26.2
# give it ~30-60s to finish first-run setup, then:
python3 poc.py # random new victim, shows auto-registration
python3 poc.py http://localhost:3000 admin # impersonate a chosen username
docker compose down -v # clean up
Как это выглядит при запуске против встроенного образа:
1) /user/settings with no header -> HTTP 303 (redirect to login = not authed)
2) /user/settings with X-WEBAUTH-USER -> HTTP 200
logged in as 'pocadmin' - no password, no token, any source IP
3) /pocadmin profile page -> HTTP 200 (account created on the fly)
Обход работает на уровне веб-сессии, а не токен-API на /api/v1/..., который игнорирует заголовок.
detect.py отправляет один безвредный пробный запрос и сравнивает его с обычным запросом. Он ничего не изменяет.
python3 detect.py https://gitea.example.com
Он выводит VULNERABLE, looks-safe или inconclusive. Запускайте его только против того, чем вы владеете или что вам разрешено тестировать.
Обновитесь до 1.26.3 / 1.26.4 или новее. Аутентификация через обратный прокси теперь включается явно, и в образе больше нет wildcard. Если вы пока не можете обновиться, задайте REVERSE_PROXY_TRUSTED_PROXIES как фактический IP-адрес или CIDR вашего прокси (никогда не *) либо отключите ENABLE_REVERSE_PROXY_AUTHENTICATION, если вы её не используете.
Я нашёл эту ошибку и сообщил о ней в Gitea 26 мая 2026 года. Я — тот самый репортёр, который указан в уведомлении Gitea, GHSA-f75j-4cw6-rmx4.
Некоторые публикации приписали это репозиторию Exploitarium вместо меня. Это неверно: это отдельная вещь от того, что опубликовал тот репозиторий. С тех пор я добился исправления нескольких таких блогов; в некоторых до сих пор содержатся ошибки.
Лицензия MIT. См. LICENSE.