Статья Traefik ForwardAuth bypass уязвимость: двойной удар CVE-2026-35051 и CVE-2026-39858

Разобранное устройство на антистатическом коврике с перерезанной дорожкой платы. Диагностический экран отображает текст об уязвимости, пальцы в синих перчатках касаются платы логическим щупом.


На стенде с Traefik v3.6.12 за Nginx-прокси один запрос с заголовком X-Forwarded-Prefix: / заставил ForwardAuth middleware вернуть 200 вместо 401 - доступ к защищённому маршруту без единого credential. Второй запрос - с X_Forwarded_Proto: https (подчёркивание вместо дефиса) - обошёл санитизацию заголовков целиком. Обе уязвимости раскрыты в апреле 2026 года, обе получили CVSS 7.8 (HIGH) по NVD (CVSS 4.0), обе эксплуатируются без аутентификации с сетевого уровня. Ниже - полная механика обеих CVE, воспроизведение на стенде, Sigma-правило и hardening-чеклист для передачи в ops-команду.

Бизнес-логика атаки: зачем ломать ForwardAuth​

ForwardAuth - стандартный паттерн делегированной аутентификации в Traefik. Каждый входящий запрос пересылается на внешний auth-сервис (Authelia, oauth2-proxy, кастомный JWT-валидатор). Сервис возвращает 200 (пропустить) или 401 (заблокировать). Этот middleware часто оказывается единственной точкой аутентификации для дашбордов Grafana, Kibana, Portainer, внутренних API и admin-панелей в Kubernetes- и Docker Swarm-деплойментах.

Обход ForwardAuth в терминах MITRE ATT&CK - Exploit Public-Facing Application (T1190, Initial Access). Атакующий без пароля и токена получает доступ ко всем маршрутам за middleware. Дальше он действует как легитимный пользователь - Valid Accounts (T1078): забирает JWT-токены из API-ответов, открывает внутренние дашборды, читает конфигурации кластера. В Kubernetes один Traefik-инстанс обычно обслуживает десятки сервисов - компрометация ForwardAuth открывает дверь ко всем сразу.

Финансовый импакт прямолинейный: если за ForwardAuth скрыт Portainer или Kubernetes Dashboard - атакующий получает управление кластером. Если внутренний API - доступ к данным клиентов и точку для pivoting во внутреннюю сеть.

CVE-2026-35051: обход аутентификации Traefik через X-Forwarded-Prefix​

1783676495167.webp

CVSS 4.0: 7.8 (HIGH). Вектор: AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:H/SI:L/SA:N. Пара SC:H/SI:L в CVSS 4.0 означает: высокое влияние на конфиденциальность downstream-систем и низкое на их целостность - атакующий читает всё, но ограничен в модификации.

CWE: CWE-345 (Insufficient Verification of Data Authenticity), CWE-501 (Trust Boundary Violation).

Затронуты: все Traefik v2 до 2.11.43, все v3 до 3.6.14, v3.7 до 3.7.0-rc.2.

EPSS: 0.27% (percentile 0.18 - ниже медианы, низкая вероятность массовой эксплуатации сейчас).

Суть проблемы: когда trustForwardHeader=false выставлен на ForwardAuth middleware и Traefik стоит за upstream proxy, заголовки X-Forwarded-For, X-Forwarded-Host, X-Forwarded-Proto корректно перестраиваются из trusted-контекста. А вот X-Forwarded-Prefix - нет. По advisory GHSA-6384-m2mw-rf54, значение от клиента проходит через upstream proxy и Traefik в неизменном виде, попадая в subrequest к auth-сервису.

Если auth-сервис принимает решения авторизации на основе X-Forwarded-Prefix - а это документированный сценарий для Authelia и ряда кастомных валидаторов - атакующий подменяет prefix на значение, которое auth-сервис считает доверенным маршрутом. Результат: 200 вместо 401.

Парадокс тут в том, что trustForwardHeader=false - рекомендуемая "безопасная" настройка. Администратор выставляет false и резонно полагает: клиентские X-Forwarded- заголовки не попадут в auth-сервис. Для трёх из четырёх стандартных X-Forwarded- это так. Для Prefix - нет. CWE-501 (Trust Boundary Violation) описывает эту ситуацию в точности: данные пересекают границу доверия без верификации.

Предусловия:
  • Traefik развёрнут за upstream proxy (AWS ALB, Cloudflare, Nginx, HAProxy, другой Traefik)
  • trustForwardHeader: false выставлен на ForwardAuth middleware
  • Auth-сервис использует X-Forwarded-Prefix для routing или authorization решений
Когда техника НЕ работает:
  • Traefik напрямую доступен из интернета без upstream proxy - тогда Traefik сам генерирует X-Forwarded-* заголовки
  • Auth-сервис не использует X-Forwarded-Prefix (проверяет только Cookie, Authorization, session token)
  • Upstream proxy явно стрипает X-Forwarded-Prefix до передачи в Traefik
[Применимо: внешний пентест при наличии Traefik за upstream proxy; внутренний пентест при multi-Traefik deployment в Kubernetes]

CVE-2026-39858: Traefik header injection через underscore-заголовки​

1783676577011.webp

CVSS 4.0: 7.8 (HIGH). Вектор: AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:H/SI:H/SA:N. Обратите внимание на SI:H вместо SI:L у CVE-2026-35051 - влияние на целостность downstream-систем тут максимальное.

CWE: CWE-290 (Authentication Bypass by Spoofing), CWE-306 (Missing Authentication for Critical Function), CWE-289 (Authentication Bypass by Alternate Name). Три CWE - три грани одной проблемы: spoofing trust-контекста, отсутствие аутентификации для критической функции и обход через альтернативное имя.

Затронуты: все Traefik v2 до 2.11.43, все v3 до 3.6.14, v3.7 до 3.7.0-rc.2.

EPSS: 0.48% (percentile 0.38 - ниже медианы). CISA SSVC: решение Track (мониторить), Exploitation - none, но Automatable - yes.

CWE-289 - Authentication Bypass by Alternate Name - буквальное описание того, что происходит. Санитизация заголовков в ForwardAuth middleware таргетирует только каноническую форму с дефисами: X-Forwarded-Proto, X-Forwarded-Host, X-Forwarded-For. Underscore-варианты - X_Forwarded_Proto, X_Forwarded_Host, X_Forwarded_For - проходят через фильтр как ни в чём не бывало и попадают в auth-бэкенд.

И вот тут начинается самое интересное: куча бэкендов нормализуют underscore и dash одинаково. Apache, Nginx в FastCGI-режиме, Python-фреймворки (Flask, Django через WSGI), Node.js - для всех них X_Forwarded_Proto и X-Forwarded-Proto одно и то же. Auth-сервис получает подменённый trust-контекст и авторизует запрос.

Ключевое отличие от CVE-2026-35051: для этой уязвимости upstream proxy НЕ обязателен. Запрос с underscore-заголовками отправляется напрямую в Traefik. Через underscore-варианты можно подменить не только маршрутный контекст, но и identity целиком: X_Forwarded_User: admin заставит auth-бэкенд считать запрос уже аутентифицированным от имени admin. По advisory, на GitHub доступен proof-of-concept для CVE-2026-39858.

Предусловия:
  • Auth-бэкенд нормализует underscore и dash в заголовках (Apache, Python WSGI, Node.js - да)
  • Traefik или upstream proxy не стрипают underscore-заголовки (по умолчанию - не стрипают)
Когда техника НЕ работает:
  • Auth-бэкенд написан на Go с net/http - Go различает underscore и dash в заголовках
  • На upstream proxy включена underscores_in_headers off (Nginx)
  • Auth-бэкенд явно отвергает запросы с underscore-заголовками
[Применимо: внешний пентест - прямой доступ к Traefik без upstream proxy; внутренний пентест - любая конфигурация с ForwardAuth]

Цепочка атаки: от header smuggling до захвата сессий​

В kill chain обе CVE занимают позицию Initial Access (T1190). Что дальше - зависит от того, что стоит за ForwardAuth.

Типичная цепочка на пентесте Kubernetes-кластера:
  1. Разведка. Определить Traefik: заголовок ответа Server: Traefik, характерная страница 404/502, эндпоинт /api/rawdata (если dashboard открыт). Определить ForwardAuth: 401 с редиректом на auth-endpoint или 403 без тела ответа
  2. Initial Access (T1190). HTTP-запрос с X-Forwarded-Prefix: / (CVE-2026-35051) или X_Forwarded_User: admin (CVE-2026-39858). Один запрос - ForwardAuth возвращает 200
  3. Valid Accounts (T1078). Атакующий действует от имени подставленного пользователя. Если auth-сервис устанавливает X-Forwarded-User в ответе через authResponseHeaders - бэкенд воспринимает запрос как аутентифицированный
  4. Credential Access (T1606.001). Если за ForwardAuth скрыт Grafana или Kibana - атакующий получает session cookies. Если API - JWT-токены в теле ответа
  5. Lateral Movement (T1550.004). Полученные cookies и токены используются для доступа к другим сервисам кластера
Chaining обеих CVE. Если auth-бэкенд использует X-Forwarded-Prefix для routing (CVE-2026-35051) И нормализует underscore-заголовки (CVE-2026-39858) - обе уязвимости работают параллельно на разных маршрутах за одним Traefik. Патч одной не закрывает вторую.

Регрессия CVE-2026-54763: почему одного патча недостаточно​

Через три месяца после патча CVE-2026-39858 выяснилось, что исправление было неполным. CVE-2026-54763 (CVSS 7.8, HIGH по NVD; CWE-178, CWE-290, CWE-345) затронула BasicAuth, DigestAuth и ForwardAuth - тот же underscore-трюк, но через identity-заголовки: X_Auth_User вместо X-Auth-User. Исправлено в v2.11.51, v3.6.22, v3.7.6. По данным 1275.ru, «разработчики уже исправляли вектор подмены заголовков аутентификации через канонические имена, однако исправление оказалось неполным».

Одновременно раскрыта CVE-2026-54764 (CVSS 6.9, MEDIUM): ForwardAuth с trustForwardHeader: false берёт X-Forwarded-Port из исходного запроса вместо санитизированного - атакующий инжектит X-Forwarded-Proto: https по HTTP, а Traefik передаёт auth-сервису X-Forwarded-Port: 443.

Три раунда обновлений ForwardAuth за три месяца. Это не единичный баг - это системная проблема парсинга заголовков.

Эксплуатация middleware bypass Traefik на пентесте​

📚 Часть контента скрыта. Этот материал доступен участникам сообщества с рангом One Level или выше
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
. Если auth-сервис использует X-Forwarded-Prefix для определения маршрута - запрос проходит. Прямой запрос к Traefik (без upstream) корректно блокируется - уязвимость проявляется только при прохождении через trusted upstream, что подтверждено в advisory GHSA-6384-m2mw-rf54.

Воспроизведение CVE-2026-39858. Upstream proxy не нужен - запрос идёт напрямую в Traefik:
Код:
curl -v -H "X_Forwarded_Proto: https" -H "X_Forwarded_Host: trusted.internal" -H "X_Forwarded_User: admin" http://traefik:80/protected-route
Если auth-бэкенд (Apache, Python-фреймворк) нормализует underscore в dash, он получит X-Forwarded-User: admin и посчитает запрос доверенным. Ответ 200 вместо 401 - middleware обойден.

Валидация в Burp Suite. Отправляйте запрос через Repeater, добавляя оба набора заголовков. Если на одном из маршрутов ответ сменился с 401 на 200 - фиксируйте bypass в отчёт. Учтите: в Traefik access log по умолчанию заголовки не логируются, поэтому атака проходит без следов, пока ops-команда не включит захват заголовков.

Детектирование header smuggling атаки в логах Traefik​

Главная проблема: по умолчанию Traefik не логирует заголовки входящих запросов. Без явной настройки underscore-заголовки проходят невидимо.

Шаг 1: включить JSON access log с заголовками. В статической конфигурации Traefik выставьте accessLog.filePath, accessLog.format: json и accessLog.fields.headers.defaultMode: keep. После этого каждый запрос будет содержать полный набор заголовков в логе.

Шаг 2: Sigma-правило для детектирования underscore-заголовков. Правило адаптировано из advisory с добавлением паттернов для identity-заголовков (покрытие CVE-2026-54763):
YAML:
title: Traefik ForwardAuth header smuggling attempt
logsource:
  product: traefik
  service: access
detection:
  selection:
    request_headers|contains:
      - "X_Forwarded_"
      - "X_Auth_"
      - "X_Forwarded_Prefix"
  condition: selection
level: high
Шаг 3: мониторинг аномалий. Ищите в логах 200/302 ответы на ForwardAuth-защищённых маршрутах от IP-адресов, которые ранее не проходили аутентификацию. Нетипичный объём запросов к auth-эндпоинтам - дополнительный индикатор.

Ограничение Sigma-правила: оно не сработает, если атакующий подменил заголовки до Traefik (на уровне скомпрометированного upstream proxy). В этом случае Traefik получает стандартные dash-заголовки, установленные upstream. Для полного покрытия нужен лог-анализ на каждом уровне proxy-цепочки.

Чеклист: патч и hardening ForwardAuth middleware​

Нумерованный список для передачи ops-команде или включения в отчёт по пентесту.
  1. Обновить Traefik до актуальных версий. Минимум для закрытия CVE-2026-35051 и CVE-2026-39858: v2.11.43 (ветка v2), v3.6.14 (ветка v3.6), v3.7.0-rc.2 (ветка v3.7). Для полного закрытия регрессии CVE-2026-54763 - обновиться до v2.11.51, v3.6.22, v3.7.6. Проверить текущую версию: traefik version. Для Kubernetes Helm: helm upgrade traefik traefik/traefik --set image.tag=v3.6.22.
  2. Ограничить заголовки в ForwardAuth через authRequestHeaders. Defense-in-depth: даже на пропатченных версиях явно перечислите допустимые заголовки:
YAML:
spec:
  forwardAuth:
    address: http://authelia:9091/api/verify
    trustForwardHeader: false
    authRequestHeaders:
      - Accept
      - Cookie
      - Authorization
    authResponseHeaders:
      - X-Forwarded-User
      - X-Forwarded-Groups
Если authRequestHeaders задан, Traefik пересылает auth-сервису только перечисленные заголовки. Все остальные - включая X-Forwarded-Prefix и underscore-варианты - отсекаются до попадания в auth-сервис. Опция доступна начиная с Traefik v2.6.
  1. Стрипать underscore-заголовки на upstream proxy. Для Nginx: директива underscores_in_headers off; в server-блоке. Для Apache: RequestHeader unset X_Forwarded_For, RequestHeader unset X_Forwarded_Host, RequestHeader unset X_Forwarded_Proto и аналогично для identity-заголовков.
  2. Включить allowHeadersWithUnderscores: false. Опция доступна в патчах CVE-2026-54763 (v2.11.51+, v3.6.22+, v3.7.6+). Отсекает заголовки с подчёркиваниями на уровне entryPoint до этапа маршрутизации.
  3. Аудит auth-бэкенда на нормализацию заголовков. Проверьте: нормализует ли ваш auth-бэкенд underscore и dash. Python (Flask, Django), Node.js, Apache в CGI-режиме - нормализуют. Go net/http - нет. Знание поведения бэкенда определяет реальный risk exposure.
  4. Тестировать патч. После обновления: curl -H "X_Forwarded_User: test" http://traefik/protected-route и curl -H "X-Forwarded-Prefix: /test" http://upstream/protected-route. Оба запроса должны возвращать 401/403. Если хотя бы один возвращает 200 - патч не применился или конфигурация осталась уязвимой.
  5. Подписаться на security advisories. GitHub: traefik/traefik, Watch, Security alerts. Регрессия CVE-2026-54763 через три месяца после первого патча показала: один цикл обновления не гарантирует закрытия всех вариаций вектора.
Паттерн trustForwardHeader=false - одна из самых опасных иллюзий безопасности в мире reverse proxy. Администратор видит параметр, читает название, делает разумный вывод: "если false - заголовки от клиента не будут доверенными". На практике это не так - и не было так ни в одной из уязвимых версий Traefik. CVE-2026-35051 показала, что X-Forwarded-Prefix просто пропущен в санитизации. CVE-2026-39858 - что underscore-варианты не попадают в фильтр. CVE-2026-54763 - что патч для underscore-варианта оказался неполным. Три раунда обновлений за три месяца, и каждый раз одна корневая причина: HTTP-заголовки допускают слишком много вариаций написания, а санитизация работает по блоклисту вместо allowlist.

Мой прогноз: следующий раунд будет про X-Forwarded-Prefix с подчёркиванием, или про заголовки с пробелами до двоеточия, или про unicode-нормализацию на стороне бэкенда. Блоклист никогда не закроет все варианты. Рабочий подход один: authRequestHeaders с явным перечислением допустимых заголовков. Если ваш ForwardAuth middleware не использует эту опцию - не имеет значения, на какой версии Traefik вы стоите. А если вы пропатчились до 2.11.43 в апреле и решили, что дело закрыто - проверьте, не пора ли накатить 2.11.51.
 
Последнее редактирование модератором:
Мы в соцсетях:

Взломай свой первый сервер и прокачай скилл — Начни игру на HackerLab

🚀 Первый раз на Codeby?
Гайд для новичков: что делать в первые 15 минут, ключевые разделы, правила
Начать здесь →
🧭 Навигатор · ИБ 2026
Не знаешь, какой трек твой?
5 направлений ИБ, реальные зарплаты и точка входа для каждого — в одном треде.
JuniorSenior+
100K → 600K+ ₽ /мес
Открыть навигатор →
🔴 Свежие CVE, 0-day и инциденты
То, о чём ChatGPT ещё не знает — обсуждаем в реальном времени
Threat Intel →
💼 Вакансии и заказы в ИБ
Pentest, SOC, DevSecOps, bug bounty — работа и проекты от проверенных компаний
Карьера в ИБ →

HackerLab