Skip to content

feat: add HTTP request smuggling skill#405

Open
sandiyochristan wants to merge 2 commits intousestrix:mainfrom
sandiyochristan:feat/http-request-smuggling-skill
Open

feat: add HTTP request smuggling skill#405
sandiyochristan wants to merge 2 commits intousestrix:mainfrom
sandiyochristan:feat/http-request-smuggling-skill

Conversation

@sandiyochristan
Copy link
Copy Markdown

Summary

HTTP request smuggling (HRS) is completely absent from the current skill set. It is a high-severity, infrastructure-level vulnerability present in virtually any application architecture using a CDN, load balancer, or reverse proxy in front of an origin server. The impact ranges from bypassing front-end authentication controls to cross-user session token capture. The SSRF, IDOR, and authentication skills do not cover this class at all.

This PR adds strix/skills/vulnerabilities/http_request_smuggling.md.

What's Added

New file: strix/skills/vulnerabilities/http_request_smuggling.md

Desync variant coverage:

  • CL.TE: Front-end uses Content-Length, back-end uses Transfer-Encoding — back-end socket poisoned with hidden request prefix
  • TE.CL: Front-end uses Transfer-Encoding, back-end uses Content-Length — front-end forwards excess body
  • H2.CL: HTTP/2 → HTTP/1.1 downgrade with injected content-length pseudo-header conflict
  • H2.TE: transfer-encoding: chunked injected via HTTP/2 headers (spec-forbidden, often passed through)

Transfer-Encoding obfuscation techniques:

  • Transfer-Encoding: xchunked, leading tab/space, duplicate TE headers, invalid chunk extensions

Exploitation scenarios:

  • Front-end security control bypass (auth, IP restriction, WAF) via smuggled prefix
  • Cross-user request capture into a reflective endpoint for session token theft
  • Response queue poisoning for wrong-user response delivery
  • WebSocket handshake hijacking via smuggled Upgrade request

Detection methodology:

  • Timing-based probe construction (CL.TE timeout, TE.CL timeout)
  • Differential response detection (second request receiving unexpected response)
  • HTTP/2 pseudo-header injection probing

Raw HTTP examples provided for each variant.

Test Plan

  • Send CL.TE timing probe (missing chunk terminator) — confirm 10+ second delay on vulnerable target
  • Send TE.CL timing probe — confirm delay with Content-Length < chunked body
  • Attempt TE obfuscation: Transfer-Encoding: xchunked — confirm desync via differential response
  • Craft a smuggled GET /admin prefix and confirm back-end serves 200 where direct request returns 403
  • Test H2.CL: send HTTP/2 request with injected content-length differing from actual body length
  • Run make check-all

Add a new vulnerability skill covering HTTP request smuggling (HRS)
across CL.TE, TE.CL, H2.CL, and H2.TE desync variants. HRS is absent
from the existing skill set despite being a distinct, high-impact
vulnerability class frequently present in any architecture using a
reverse proxy or CDN in front of an application server.

Coverage:
- CL.TE: front-end uses Content-Length, back-end uses Transfer-Encoding
- TE.CL: front-end uses Transfer-Encoding, back-end uses Content-Length
- H2.CL: HTTP/2 front-end downgrades to HTTP/1.1 with injected Content-Length
- H2.TE: Transfer-Encoding header injection through HTTP/2 desync
- Transfer-Encoding obfuscation techniques (tab, space, duplicate, xchunked)
- Front-end security control bypass via smuggled prefix
- Cross-user request capture for session token theft
- Response queue poisoning and WebSocket handshake hijacking
- Timing-based and differential response detection methodology
- HTTP/2 specific probing techniques

Includes raw HTTP examples for each variant, step-by-step testing
methodology, exploitation PoCs, false-positive conditions, and
infrastructure topology guidance.
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 28, 2026

Greptile Summary

This PR adds strix/skills/vulnerabilities/http_request_smuggling.md, a new skill covering HTTP request smuggling (CL.TE, TE.CL, H2.CL, H2.TE). The structure, section layout, and frontmatter all match the conventions of existing skills, and the overall coverage of attack variants, exploitation scenarios, detection methodology, false-positive guidance, and pro tips is thorough and well-organised.

However, there are a few technical inaccuracies that should be corrected before merging, since agents load these skills verbatim and would act on incorrect information:

  • Inverted TE.CL timing-probe description (P1): The "Timing-Based Detection" section describes the TE.CL probe as requiring Content-Length set to fewer bytes than the chunk content, but the correct mechanism is the opposite — Content-Length must be larger than the bytes actually provided so the back-end blocks waiting for more data. Setting CL < chunked body causes differential-response socket poisoning, not a timeout.
  • content-length mis-labelled as a pseudo-header (P2): Both the H2.CL core-concept explanation (line 75) and Pro Tip [Bug]: GPT-5 - Unsupported parameter: stop words #4 (line 248) refer to content-length as a pseudo-header and even write it as :content-length. HTTP/2 pseudo-headers are exclusively the four :method/:path/:authority/:scheme fields; content-length is a regular header.
  • Miscalculated Content-Length values in PoC examples (P2): The outer Content-Length declarations in the Front-End Bypass PoC (116) and Cross-User Capture PoC (129) do not match the actual byte counts of the bodies shown (~99 and ~120 respectively). Sending these verbatim would produce malformed requests.
  • \\x20 escape not rendered in Markdown code blocks (P2): The obfuscation examples use \\x20 as a space-byte representation, but inside a fenced code block this is a literal four-character string, which an agent would include verbatim rather than as a space character.

Confidence Score: 4/5

Safe to merge after fixing the inverted TE.CL timing-probe description — the remaining issues are accuracy improvements that reduce agent confusion but are not blocking.

One P1 correctness issue: the TE.CL timing-probe description is mechanically inverted and would cause an agent to construct the wrong type of probe (socket-poisoning instead of timeout). The remaining P2 items (pseudo-header terminology, PoC Content-Length values, \x20 representation) are meaningful accuracy concerns but do not render the skill non-functional. Score is 4 rather than 5 because the P1 item is a factual error in the core detection methodology section.

strix/skills/vulnerabilities/http_request_smuggling.md — specifically the TE.CL timing-probe description, H2.CL pseudo-header references, and PoC Content-Length values.

Important Files Changed

Filename Overview
strix/skills/vulnerabilities/http_request_smuggling.md New HRS skill with solid structural coverage of CL.TE, TE.CL, H2.CL, H2.TE variants, but contains a technically incorrect TE.CL timing-probe description, misuse of HTTP/2 pseudo-header terminology, and miscalculated Content-Length values in PoC examples.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: strix/skills/vulnerabilities/http_request_smuggling.md
Line: 176

Comment:
**TE.CL timing-probe description is inverted**

The description says "Content-Length set to *fewer* bytes than the chunk content. TE.CL back-end waits for more bytes per Content-Length." These two sentences contradict each other and the mechanics are wrong.

In TE.CL, the **front-end uses Transfer-Encoding** (so it reads until the `0\r\n\r\n` terminator and happily forwards a complete request), while the **back-end uses Content-Length**. For a *timing* probe you want the back-end to hang — that means `Content-Length` must declare **more bytes than the body actually provides**, so the back-end waits for additional data that never arrives.

If Content-Length is *fewer* bytes than the chunked body, the back-end simply reads its allotted bytes and returns a response immediately — this causes **socket poisoning / differential-response detection**, not a timeout.

Suggested fix:

```suggestion
**TE.CL:** Send a request with a complete chunked body (including the `0\r\n\r\n` terminator so the front-end is satisfied) but with `Content-Length` set to **more** bytes than the body actually provides. The back-end, using Content-Length, waits for the remaining bytes that never arrive — producing a 10–30 second timeout.
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: strix/skills/vulnerabilities/http_request_smuggling.md
Line: 75

Comment:
**`content-length` is not an HTTP/2 pseudo-header**

The sentence describes the injected header as being placed in "HTTP/2 request pseudo-headers." HTTP/2 pseudo-headers are the four fields that begin with `:``:method`, `:path`, `:authority`, and `:scheme`. `content-length` is a *regular* header in HTTP/2, not a pseudo-header. The code example correctly shows it without the `:` prefix, but the prose is misleading.

The same incorrect term appears again in **Pro Tip #4 (line 248)**, which refers to `":content-length" pseudo-header` — there is no such HTTP/2 pseudo-header; the correct name is just `content-length`.

```suggestion
But when the front-end downgrades to HTTP/1.1 for the back-end, an attacker can inject a `content-length` header in the HTTP/2 request that conflicts with the actual body length:
```

And at line 248:
```
H2.CL is the most impactful modern variant — many CDNs translate HTTP/2 to HTTP/1.1 and inject `Content-Length` from the `content-length` regular header sent in the HTTP/2 request.
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: strix/skills/vulnerabilities/http_request_smuggling.md
Line: 110

Comment:
**Content-Length values in PoC examples appear miscalculated**

The `Content-Length: 116` on this line (the Front-End Bypass PoC) and `Content-Length: 129` on line 132 (the Cross-User Capture PoC) are the outer request's Content-Length — they must match the exact byte count of the entire smuggled body (including CRLF line endings).

Quick manual count for the Bypass PoC body (assuming `\r\n` line endings):
- `0\r\n` = 3
- `\r\n` = 2
- `GET /admin HTTP/1.1\r\n` = 21
- `Host: target.com\r\n` = 18
- `X-Forwarded-Host: target.com\r\n` = 30
- `Content-Length: 10\r\n` = 20
- `\r\n` = 2
- `x=1` = 3

**Total ≈ 99**, not 116. If an agent uses the skill verbatim it will send a malformed outer request that most servers will reject or mis-parse.

Because the Validation section explicitly asks for "exact raw bytes," these values should be corrected, or the examples should include a clear callout that the Content-Length must be recomputed to match actual byte counts before use.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: strix/skills/vulnerabilities/http_request_smuggling.md
Line: 186

Comment:
**`\x20` is a literal four-character string in a Markdown code block**

Inside a fenced code block, `\x20` is rendered as the four characters `\`, `x`, `2`, `0` — not as a space byte (0x20). An agent reading this skill may literally include `\x20` in a header value, producing an invalid header rather than the intended leading-space obfuscation.

Similarly, line 188 has the comment `# tab before value` but no tab character is visible — the obfuscated tab should be represented as an actual tab or documented with a clear note (e.g. `<TAB>`).

```suggestion
Transfer-Encoding: xchunked        # non-standard value, some FE ignore, BE accept
Transfer-Encoding: chunked         # leading space before value (send literal 0x20 before "chunked")
Transfer-Encoding:	chunked        # tab character before value (send literal 0x09 before "chunked")
Transfer-Encoding: x
Transfer-Encoding: chunked         # duplicate TE headers, BE uses last
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "feat: add HTTP request smuggling skill" | Re-trigger Greptile

```
If response is delayed 10–30 seconds, CL.TE desync likely.

**TE.CL:** Send a request with `Transfer-Encoding` present but `Content-Length` set to fewer bytes than the chunk content. TE.CL back-end waits for more bytes per Content-Length.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 TE.CL timing-probe description is inverted

The description says "Content-Length set to fewer bytes than the chunk content. TE.CL back-end waits for more bytes per Content-Length." These two sentences contradict each other and the mechanics are wrong.

In TE.CL, the front-end uses Transfer-Encoding (so it reads until the 0\r\n\r\n terminator and happily forwards a complete request), while the back-end uses Content-Length. For a timing probe you want the back-end to hang — that means Content-Length must declare more bytes than the body actually provides, so the back-end waits for additional data that never arrives.

If Content-Length is fewer bytes than the chunked body, the back-end simply reads its allotted bytes and returns a response immediately — this causes socket poisoning / differential-response detection, not a timeout.

Suggested fix:

Suggested change
**TE.CL:** Send a request with `Transfer-Encoding` present but `Content-Length` set to fewer bytes than the chunk content. TE.CL back-end waits for more bytes per Content-Length.
**TE.CL:** Send a request with a complete chunked body (including the `0\r\n\r\n` terminator so the front-end is satisfied) but with `Content-Length` set to **more** bytes than the body actually provides. The back-end, using Content-Length, waits for the remaining bytes that never arrive — producing a 10–30 second timeout.
Prompt To Fix With AI
This is a comment left during a code review.
Path: strix/skills/vulnerabilities/http_request_smuggling.md
Line: 176

Comment:
**TE.CL timing-probe description is inverted**

The description says "Content-Length set to *fewer* bytes than the chunk content. TE.CL back-end waits for more bytes per Content-Length." These two sentences contradict each other and the mechanics are wrong.

In TE.CL, the **front-end uses Transfer-Encoding** (so it reads until the `0\r\n\r\n` terminator and happily forwards a complete request), while the **back-end uses Content-Length**. For a *timing* probe you want the back-end to hang — that means `Content-Length` must declare **more bytes than the body actually provides**, so the back-end waits for additional data that never arrives.

If Content-Length is *fewer* bytes than the chunked body, the back-end simply reads its allotted bytes and returns a response immediately — this causes **socket poisoning / differential-response detection**, not a timeout.

Suggested fix:

```suggestion
**TE.CL:** Send a request with a complete chunked body (including the `0\r\n\r\n` terminator so the front-end is satisfied) but with `Content-Length` set to **more** bytes than the body actually provides. The back-end, using Content-Length, waits for the remaining bytes that never arrive — producing a 10–30 second timeout.
```

How can I resolve this? If you propose a fix, please make it concise.


### H2.CL — HTTP/2 Front-end Downgrades to HTTP/1.1, Injects Content-Length

HTTP/2 has no `Content-Length` vs `TE` ambiguity in its own framing. But when the front-end downgrades to HTTP/1.1 for the back-end, an attacker can inject a `Content-Length` header in the HTTP/2 request pseudo-headers that conflicts with the actual body length:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 content-length is not an HTTP/2 pseudo-header

The sentence describes the injected header as being placed in "HTTP/2 request pseudo-headers." HTTP/2 pseudo-headers are the four fields that begin with ::method, :path, :authority, and :scheme. content-length is a regular header in HTTP/2, not a pseudo-header. The code example correctly shows it without the : prefix, but the prose is misleading.

The same incorrect term appears again in Pro Tip #4 (line 248), which refers to ":content-length" pseudo-header — there is no such HTTP/2 pseudo-header; the correct name is just content-length.

Suggested change
HTTP/2 has no `Content-Length` vs `TE` ambiguity in its own framing. But when the front-end downgrades to HTTP/1.1 for the back-end, an attacker can inject a `Content-Length` header in the HTTP/2 request pseudo-headers that conflicts with the actual body length:
But when the front-end downgrades to HTTP/1.1 for the back-end, an attacker can inject a `content-length` header in the HTTP/2 request that conflicts with the actual body length:

And at line 248:

H2.CL is the most impactful modern variant — many CDNs translate HTTP/2 to HTTP/1.1 and inject `Content-Length` from the `content-length` regular header sent in the HTTP/2 request.
Prompt To Fix With AI
This is a comment left during a code review.
Path: strix/skills/vulnerabilities/http_request_smuggling.md
Line: 75

Comment:
**`content-length` is not an HTTP/2 pseudo-header**

The sentence describes the injected header as being placed in "HTTP/2 request pseudo-headers." HTTP/2 pseudo-headers are the four fields that begin with `:``:method`, `:path`, `:authority`, and `:scheme`. `content-length` is a *regular* header in HTTP/2, not a pseudo-header. The code example correctly shows it without the `:` prefix, but the prose is misleading.

The same incorrect term appears again in **Pro Tip #4 (line 248)**, which refers to `":content-length" pseudo-header` — there is no such HTTP/2 pseudo-header; the correct name is just `content-length`.

```suggestion
But when the front-end downgrades to HTTP/1.1 for the back-end, an attacker can inject a `content-length` header in the HTTP/2 request that conflicts with the actual body length:
```

And at line 248:
```
H2.CL is the most impactful modern variant — many CDNs translate HTTP/2 to HTTP/1.1 and inject `Content-Length` from the `content-length` regular header sent in the HTTP/2 request.
```

How can I resolve this? If you propose a fix, please make it concise.

```http
POST /not-restricted HTTP/1.1
Host: target.com
Content-Length: 116
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Content-Length values in PoC examples appear miscalculated

The Content-Length: 116 on this line (the Front-End Bypass PoC) and Content-Length: 129 on line 132 (the Cross-User Capture PoC) are the outer request's Content-Length — they must match the exact byte count of the entire smuggled body (including CRLF line endings).

Quick manual count for the Bypass PoC body (assuming \r\n line endings):

  • 0\r\n = 3
  • \r\n = 2
  • GET /admin HTTP/1.1\r\n = 21
  • Host: target.com\r\n = 18
  • X-Forwarded-Host: target.com\r\n = 30
  • Content-Length: 10\r\n = 20
  • \r\n = 2
  • x=1 = 3

Total ≈ 99, not 116. If an agent uses the skill verbatim it will send a malformed outer request that most servers will reject or mis-parse.

Because the Validation section explicitly asks for "exact raw bytes," these values should be corrected, or the examples should include a clear callout that the Content-Length must be recomputed to match actual byte counts before use.

Prompt To Fix With AI
This is a comment left during a code review.
Path: strix/skills/vulnerabilities/http_request_smuggling.md
Line: 110

Comment:
**Content-Length values in PoC examples appear miscalculated**

The `Content-Length: 116` on this line (the Front-End Bypass PoC) and `Content-Length: 129` on line 132 (the Cross-User Capture PoC) are the outer request's Content-Length — they must match the exact byte count of the entire smuggled body (including CRLF line endings).

Quick manual count for the Bypass PoC body (assuming `\r\n` line endings):
- `0\r\n` = 3
- `\r\n` = 2
- `GET /admin HTTP/1.1\r\n` = 21
- `Host: target.com\r\n` = 18
- `X-Forwarded-Host: target.com\r\n` = 30
- `Content-Length: 10\r\n` = 20
- `\r\n` = 2
- `x=1` = 3

**Total ≈ 99**, not 116. If an agent uses the skill verbatim it will send a malformed outer request that most servers will reject or mis-parse.

Because the Validation section explicitly asks for "exact raw bytes," these values should be corrected, or the examples should include a clear callout that the Content-Length must be recomputed to match actual byte counts before use.

How can I resolve this? If you propose a fix, please make it concise.


```http
Transfer-Encoding: xchunked # non-standard value, some FE ignore, BE accept
Transfer-Encoding:\x20chunked # leading space
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 \x20 is a literal four-character string in a Markdown code block

Inside a fenced code block, \x20 is rendered as the four characters \, x, 2, 0 — not as a space byte (0x20). An agent reading this skill may literally include \x20 in a header value, producing an invalid header rather than the intended leading-space obfuscation.

Similarly, line 188 has the comment # tab before value but no tab character is visible — the obfuscated tab should be represented as an actual tab or documented with a clear note (e.g. <TAB>).

Suggested change
Transfer-Encoding:\x20chunked # leading space
Transfer-Encoding: xchunked # non-standard value, some FE ignore, BE accept
Transfer-Encoding: chunked # leading space before value (send literal 0x20 before "chunked")
Transfer-Encoding: chunked # tab character before value (send literal 0x09 before "chunked")
Transfer-Encoding: x
Transfer-Encoding: chunked # duplicate TE headers, BE uses last
Prompt To Fix With AI
This is a comment left during a code review.
Path: strix/skills/vulnerabilities/http_request_smuggling.md
Line: 186

Comment:
**`\x20` is a literal four-character string in a Markdown code block**

Inside a fenced code block, `\x20` is rendered as the four characters `\`, `x`, `2`, `0` — not as a space byte (0x20). An agent reading this skill may literally include `\x20` in a header value, producing an invalid header rather than the intended leading-space obfuscation.

Similarly, line 188 has the comment `# tab before value` but no tab character is visible — the obfuscated tab should be represented as an actual tab or documented with a clear note (e.g. `<TAB>`).

```suggestion
Transfer-Encoding: xchunked        # non-standard value, some FE ignore, BE accept
Transfer-Encoding: chunked         # leading space before value (send literal 0x20 before "chunked")
Transfer-Encoding:	chunked        # tab character before value (send literal 0x09 before "chunked")
Transfer-Encoding: x
Transfer-Encoding: chunked         # duplicate TE headers, BE uses last
```

How can I resolve this? If you propose a fix, please make it concise.

Ahmex000 added a commit to Ahmex000/strix that referenced this pull request Mar 28, 2026
Add strix/skills/vulnerabilities/http_request_smuggling.md covering CL.TE, TE.CL, H2.CL, H2.TE desync techniques, detection methodology, exploitation scenarios, and validation steps.

Cherry-picked from usestrix#405.
…th values, \x20 representation

Four reviewer findings addressed:

P1 — TE.CL timing-probe description inverted: previous text said
'Content-Length set to fewer bytes than the chunk content' which
describes socket-poisoning behavior (differential response), not a
timeout. Corrected to: send a complete chunked body with CL set to MORE
bytes than provided so the back-end waits for data that never arrives.
Also corrected Testing Methodology step 3 to match.

P2 — pseudo-header terminology: 'content-length' is a regular HTTP/2
header, not a pseudo-header (pseudo-headers are exclusively :method,
:path, :authority, :scheme). Fixed the H2.CL explanation (line 75),
HTTP/2-specific detection bullet, and Pro Tip usestrix#4 which referred to
':content-length pseudo-header'.

P2 — PoC Content-Length values: outer Content-Length in the bypass PoC
corrected from 116 to 100 (actual byte count of the body shown); capture
PoC corrected from 129 to 120.

P2 — \x20 representation: replaced the \x20 escape sequence in the code
block (which renders as a literal four-character string, not a space byte)
with an explanatory comment and actual whitespace characters so the intent
is unambiguous.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant