# HTTP Request Smuggling due to CR-to-Hyphen conversion

Node.js converts CR in header names to hyphen, so Content[CR]Length becomes Content-Length, desyncing with front-end proxies that ignore the malformed header.

- Payout: hidden
- Severity: high
- Program: Node.js
- Found by: amitklein
- Disclosed: 2020-10-17
- CVE: CVE-2020-8201
- Write-up quality: 7/10
- Original: https://hackerone.com/reports/922597
- Library page: https://bugbountylibrary.com/r/h1%3A922597
- Tags: area:web domain:web impact:data-leak impact:integrity kind:bounty platform:hackerone sev:high tech:nodejs technique:parser-differential vuln:request-smuggling

**Target:** Node.js HTTP header parser (llhttp)
**Root cause:** Node.js normalizes a bare CR byte in header names to a hyphen before parsing, turning the non-standard `Content[CR]Length` into a valid `Content-Length`. Proxies that reject/ignore the malformed header treat the body as zero-length, creating a CL desync.
**Steps:**
1. Send a request with header `Content[CR]Length: 42` (literal CR byte inside the header name) followed by `Connection: Keep-Alive`.
2. Front-end proxy ignores the invalid header, assumes body length 0, forwards only up to the next request boundary.
3. Node.js converts CR to hyphen, sees `Content-Length: 42`, and consumes the next 42 bytes as the body.
4. Craft the following bytes so that after Node discards 42 bytes, the remaining stream begins with `GET /node_sees_this HTTP/1.1`, which Node parses as a new request while the proxy sees `GET /proxy_sees_this`.
5. Observe the smuggled request being processed by Node while the proxy treats it as a separate legitimate request.
**How found:** Observed that Node.js accepts a header name containing a raw CR and normalizes it to a hyphen, producing a valid Content-Length that standard proxies would not recognize — a parser differential between the front-end and Node.
**Exploitation:** Attacker sends a crafted keep-alive stream where the front-end proxy and Node.js disagree on request boundaries; the smuggled prefix poisons the next request on the shared connection, enabling cache poisoning, session hijacking, or XSS against other users.
**Insight:** Test header names containing control bytes (CR, LF, NUL, whitespace) against the backend parser: any normalization that turns an invalid name into a recognized one (CR→hyphen here) creates a desync primitive with proxies that reject the original.

