Skip to content

feat: add HTTP request smuggling skill#405

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

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

Conversation

@sandiyochristan
Copy link
Copy Markdown
Contributor

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 a new skill file covering HTTP request smuggling (HRS), including CL.TE, TE.CL, H2.CL, and H2.TE desync variants with detection probes, exploitation PoCs, and a remediation summary. Several issues flagged in the previous review round (TE.CL probe inversion, content-length pseudo-header misnomer, \\x20 literal) have been addressed in this version.

  • The TE.CL timing-probe description is now correct: it specifies Content-Length larger than the actual body to force a back-end timeout.
  • H2.CL correctly identifies content-length as a regular HTTP/2 header, not a pseudo-header, in both the body text and Pro Tip [Bug]: GPT-5 - Unsupported parameter: stop words #4.
  • Two entries in the Transfer-Encoding Obfuscation section still represent CRLF as the four-character string \ \ inside a code block rather than actual bytes; agents following these verbatim would produce broken requests.

Confidence Score: 4/5

The skill file is largely accurate and well-structured; one obfuscation technique section encodes CRLF as a literal four-character string, which would cause those techniques to silently fail when an agent follows the instructions verbatim.

The literal-string issue in the Transfer-Encoding Obfuscation section is the same class of representational problem that was previously fixed for \x20 — an agent constructing requests from these lines would send invalid headers and get no useful signal from the technique. That present defect in the changed file prevents a perfect score, but nothing else in the skill appears to be materially wrong.

strix/skills/vulnerabilities/http_request_smuggling.md — specifically the Transfer-Encoding Obfuscation section at lines 198–199.

Important Files Changed

Filename Overview
strix/skills/vulnerabilities/http_request_smuggling.md New skill file covering CL.TE, TE.CL, H2.CL, H2.TE smuggling variants. Previously flagged issues (TE.CL probe inversion, pseudo-header terminology, \x20 literal) are addressed, but two obfuscation entries still use the literal string \r\n instead of actual CRLF bytes, which causes those techniques to silently fail when followed verbatim.
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
strix/skills/vulnerabilities/http_request_smuggling.md:198-199
The two header-injection obfuscation entries on these lines use the four-character string `
` inside a fenced code block, not actual CRLF bytes. An agent reading this skill and constructing requests verbatim would include the literal characters `\`, `r`, `\`, `n` in the header value — HTTP libraries reject or pass this through as a single opaque string, so the injection produces no header separation and the technique silently fails. The entries need a prose note (like the tab entry on line 187) or the literal CRLF must be represented with a `<CRLF>` placeholder and a clear callout that real CRLF bytes must be injected at that position. This is the same representation problem that previously affected `\x20` in the Detection section.

```suggestion
X: X<CRLF>Transfer-Encoding: chunked # header injection — inject actual CRLF bytes at <CRLF>, not the literal string \r\n
Transfer-Encoding: chunked<CRLF>Transfer-Encoding: x  # TE twice — inject actual CRLF bytes at <CRLF>
```

Reviews (2): Last reviewed commit: "fix: correct TE.CL probe, pseudo-header ..." | 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.
@bearsyankees
Copy link
Copy Markdown
Collaborator

@greptile

Comment on lines +198 to +199
X: X\r\nTransfer-Encoding: chunked # header injection into existing header value
Transfer-Encoding: chunked\r\nTransfer-Encoding: x # TE twice
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 The two header-injection obfuscation entries on these lines use the four-character string inside a fenced code block, not actual CRLF bytes. An agent reading this skill and constructing requests verbatim would include the literal characters \, r, \, n in the header value — HTTP libraries reject or pass this through as a single opaque string, so the injection produces no header separation and the technique silently fails. The entries need a prose note (like the tab entry on line 187) or the literal CRLF must be represented with a <CRLF> placeholder and a clear callout that real CRLF bytes must be injected at that position. This is the same representation problem that previously affected \x20 in the Detection section.

Suggested change
X: X\r\nTransfer-Encoding: chunked # header injection into existing header value
Transfer-Encoding: chunked\r\nTransfer-Encoding: x # TE twice
X: X<CRLF>Transfer-Encoding: chunked # header injection — inject actual CRLF bytes at <CRLF>, not the literal string \r\n
Transfer-Encoding: chunked<CRLF>Transfer-Encoding: x # TE twice — inject actual CRLF bytes at <CRLF>
Prompt To Fix With AI
This is a comment left during a code review.
Path: strix/skills/vulnerabilities/http_request_smuggling.md
Line: 198-199

Comment:
The two header-injection obfuscation entries on these lines use the four-character string `
` inside a fenced code block, not actual CRLF bytes. An agent reading this skill and constructing requests verbatim would include the literal characters `\`, `r`, `\`, `n` in the header value — HTTP libraries reject or pass this through as a single opaque string, so the injection produces no header separation and the technique silently fails. The entries need a prose note (like the tab entry on line 187) or the literal CRLF must be represented with a `<CRLF>` placeholder and a clear callout that real CRLF bytes must be injected at that position. This is the same representation problem that previously affected `\x20` in the Detection section.

```suggestion
X: X<CRLF>Transfer-Encoding: chunked # header injection — inject actual CRLF bytes at <CRLF>, not the literal string \r\n
Transfer-Encoding: chunked<CRLF>Transfer-Encoding: x  # TE twice — inject actual CRLF bytes at <CRLF>
```

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

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.

2 participants