На стенде с 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
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
CVE-2026-39858: Traefik header injection через underscore-заголовки
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-заголовками
Цепочка атаки: от header smuggling до захвата сессий
В kill chain обе CVE занимают позицию Initial Access (T1190). Что дальше - зависит от того, что стоит за ForwardAuth.Типичная цепочка на пентесте Kubernetes-кластера:
- Разведка. Определить Traefik: заголовок ответа
Server: Traefik, характерная страница 404/502, эндпоинт/api/rawdata(если dashboard открыт). Определить ForwardAuth: 401 с редиректом на auth-endpoint или 403 без тела ответа - Initial Access (T1190). HTTP-запрос с
X-Forwarded-Prefix: /(CVE-2026-35051) илиX_Forwarded_User: admin(CVE-2026-39858). Один запрос - ForwardAuth возвращает 200 - Valid Accounts (T1078). Атакующий действует от имени подставленного пользователя. Если auth-сервис устанавливает X-Forwarded-User в ответе через
authResponseHeaders- бэкенд воспринимает запрос как аутентифицированный - Credential Access (T1606.001). Если за ForwardAuth скрыт Grafana или Kibana - атакующий получает session cookies. Если API - JWT-токены в теле ответа
- Lateral Movement (T1550.004). Полученные cookies и токены используются для доступа к другим сервисам кластера
Регрессия 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 или выше
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
Воспроизведение 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
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
Ограничение Sigma-правила: оно не сработает, если атакующий подменил заголовки до Traefik (на уровне скомпрометированного upstream proxy). В этом случае Traefik получает стандартные dash-заголовки, установленные upstream. Для полного покрытия нужен лог-анализ на каждом уровне proxy-цепочки.
Чеклист: патч и hardening ForwardAuth middleware
Нумерованный список для передачи ops-команде или включения в отчёт по пентесту.- Обновить 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. - Ограничить заголовки в 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.- Стрипать 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-заголовков. - Включить allowHeadersWithUnderscores: false. Опция доступна в патчах CVE-2026-54763 (v2.11.51+, v3.6.22+, v3.7.6+). Отсекает заголовки с подчёркиваниями на уровне entryPoint до этапа маршрутизации.
- Аудит auth-бэкенда на нормализацию заголовков. Проверьте: нормализует ли ваш auth-бэкенд underscore и dash. Python (Flask, Django), Node.js, Apache в CGI-режиме - нормализуют. Go
net/http- нет. Знание поведения бэкенда определяет реальный risk exposure. - Тестировать патч. После обновления:
curl -H "X_Forwarded_User: test" http://traefik/protected-routeиcurl -H "X-Forwarded-Prefix: /test" http://upstream/protected-route. Оба запроса должны возвращать 401/403. Если хотя бы один возвращает 200 - патч не применился или конфигурация осталась уязвимой. - Подписаться на 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.
Последнее редактирование модератором: