Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 30 additions & 19 deletions docs/content/docs/rfc-requirement-dashboard.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: "RFC Requirement Dashboard"
description: "Complete RFC 2119 requirement-level analysis for all 172 Http11Probe tests"
description: "Complete RFC 2119 requirement-level analysis for all 183 Http11Probe tests"
weight: 2
breadcrumbs: false
---
Expand All @@ -11,18 +11,18 @@ This dashboard classifies every Http11Probe test by its [RFC 2119](https://www.r

| Requirement Level | Count | Meaning (RFC 2119) |
|---|---|---|
| **MUST** | 96 | Absolute requirement — no compliant implementation may deviate |
| **MUST** | 103 | Absolute requirement — no compliant implementation may deviate |
| **SHOULD** | 29 | Recommended — valid exceptions exist but must be understood |
| **MAY** | 10 | Truly optional — either behavior is fully compliant |
| **"ought to"** | 1 | Weaker than SHOULD — recommended but not normative |
| **Unscored** | 25 | Informational — no pass/fail judgement |
| **Unscored** | 29 | Informational — no pass/fail judgement |
| **N/A** | 11 | Best-practice / no single RFC verb applies |

**Total: 172 tests**
**Total: 183 tests**

---

## MUST-Level Requirements (96 tests)
## MUST-Level Requirements (103 tests)

These tests enforce absolute RFC requirements. A compliant server has no discretion — it **MUST** behave as specified.

Expand Down Expand Up @@ -99,11 +99,18 @@ The RFC requires rejection, but the mechanism (400 status or connection close) h
| 56 | `SMUG-CLTE-KEEPALIVE` | Smuggling | [RFC 9112 §6.1](https://www.rfc-editor.org/rfc/rfc9112#section-6.1) | CL+TE conflict with explicit `Connection: keep-alive`. **MUST** close connection regardless of keep-alive. |
| 57 | `SMUG-CLTE-DESYNC` | Smuggling | [RFC 9112 §6.1](https://www.rfc-editor.org/rfc/rfc9112#section-6.1) | Classic CL.TE desync: CL=6 with TE=chunked body `0\r\n\r\nX`. Poison byte after CL boundary confirms desync. **MUST** close connection. |
| 58 | `SMUG-TECL-DESYNC` | Smuggling | [RFC 9112 §6.1](https://www.rfc-editor.org/rfc/rfc9112#section-6.1) | Reverse TE.CL desync: TE=chunked terminates at `0\r\n\r\n` but CL=30. Extra bytes on wire confirm desync. **MUST** close connection. |
| 59 | `SMUG-CHUNK-SIZE-PLUS` | Smuggling | [RFC 9112 §7.1](https://www.rfc-editor.org/rfc/rfc9112#section-7.1) | Grammar: `chunk-size = 1*HEXDIG`. Leading `+` is not HEXDIG; invalid chunk framing **MUST** be rejected. |
| 60 | `SMUG-CHUNK-SIZE-TRAILING-OWS` | Smuggling | [RFC 9112 §7.1](https://www.rfc-editor.org/rfc/rfc9112#section-7.1) | Grammar: `chunk-size = 1*HEXDIG`. Trailing whitespace in chunk-size is invalid syntax and **MUST** be rejected. |
| 61 | `SMUG-CHUNK-EXT-INVALID-TOKEN` | Smuggling | [RFC 9112 §7.1.1](https://www.rfc-editor.org/rfc/rfc9112#section-7.1.1) | Grammar: `chunk-ext-name = token`. `[` is not a valid token character, so the chunk extension is invalid and **MUST** be rejected. |
| 62 | `SMUG-OPTIONS-TE-OBS-FOLD` | Smuggling | [RFC 9112 §5.2](https://www.rfc-editor.org/rfc/rfc9112#section-5.2) | "A server that receives an obs-fold in a request message ... **MUST** either reject the message by sending a 400 (Bad Request) ... or replace each received obs-fold with one or more SP octets." |
| 63 | `SMUG-CHUNK-INVALID-SIZE-DESYNC` | Smuggling | [RFC 9112 §7.1](https://www.rfc-editor.org/rfc/rfc9112#section-7.1) | Sequence test with invalid `+0` chunk-size plus poison byte. Since `chunk-size = 1*HEXDIG`, this framing error **MUST** be rejected to prevent desync. |
| 54 | `COMP-CONNECTION-CLOSE` | Compliance | [RFC 9112 §9.6](https://www.rfc-editor.org/rfc/rfc9112#section-9.6) | "A server that receives a 'close' connection option **MUST** initiate closure of the connection after it sends the final response to the request that contained the 'close' connection option." |
| 55 | `COMP-OPTIONS-STAR` | Compliance | [RFC 9112 §3.2.4](https://www.rfc-editor.org/rfc/rfc9112#section-3.2.4) | The asterisk-form `*` is defined only for OPTIONS. A valid OPTIONS * request **MUST** be accepted. |
| 56 | `COMP-POST-CL-BODY` | Compliance | [RFC 9112 §6.2](https://www.rfc-editor.org/rfc/rfc9112#section-6.2) | "If a valid Content-Length header field is present without Transfer-Encoding, its decimal value defines the expected message body length in octets." Server **MUST** accept a well-formed POST with matching body. |
| 57 | `COMP-POST-CL-ZERO` | Compliance | [RFC 9112 §6.2](https://www.rfc-editor.org/rfc/rfc9112#section-6.2) | Content-Length: 0 is a valid 1*DIGIT value. Server **MUST** accept zero-length body. |
| 58 | `COMP-POST-NO-CL-NO-TE` | Compliance | [RFC 9112 §6.3](https://www.rfc-editor.org/rfc/rfc9112#section-6.3) | "If this is a request message and none of the above are true, then the message body length is zero (no message body is present)." Server **MUST** treat as zero-length. |
| 59 | `COMP-RANGE-POST` | Compliance | [RFC 9110 §14.2](https://www.rfc-editor.org/rfc/rfc9110#section-14.2) | "A server **MUST** ignore a Range header field received with a request method other than GET." |
| 60 | `COMP-UPGRADE-HTTP10` | Compliance | [RFC 9110 §7.8](https://www.rfc-editor.org/rfc/rfc9110#section-7.8) | "A server **MUST** ignore an Upgrade header field that is received in an HTTP/1.0 request." |
| 59 | `COMP-CHUNKED-BODY` | Compliance | [RFC 9112 §7.1](https://www.rfc-editor.org/rfc/rfc9112#section-7.1) | "A recipient **MUST** be able to parse and decode the chunked transfer coding." |
| 60 | `COMP-CHUNKED-MULTI` | Compliance | [RFC 9112 §7.1](https://www.rfc-editor.org/rfc/rfc9112#section-7.1) | Same — multi-chunk is the standard chunked format. **MUST** accept. |
| 61 | `COMP-CHUNKED-EMPTY` | Compliance | [RFC 9112 §7.1](https://www.rfc-editor.org/rfc/rfc9112#section-7.1) | A zero-length chunked body (just `0\r\n\r\n`) is valid. **MUST** accept. |
Expand Down Expand Up @@ -205,7 +212,7 @@ Weaker than SHOULD — recommends but does not normatively require.

---

## Unscored Tests (25 tests)
## Unscored Tests (29 tests)

These tests are informational — they produce warnings but never fail.

Expand Down Expand Up @@ -236,6 +243,10 @@ These tests are informational — they produce warnings but never fail.
| 23 | `COMP-RANGE-INVALID` | Compliance | [RFC 9110 §14.2](https://www.rfc-editor.org/rfc/rfc9110#section-14.2) | "A server **MAY** ignore the Range header field." Invalid Range syntax — 2xx or 416 both acceptable. |
| 24 | `COMP-POST-UNSUPPORTED-CT` | Compliance | [RFC 9110 §15.5.16](https://www.rfc-editor.org/rfc/rfc9110#section-15.5.16) | POST with unknown Content-Type — 415 or 2xx both acceptable. |
| 25 | `SMUG-PIPELINE-SAFE` | Smuggling | [RFC 9112 §9.3](https://www.rfc-editor.org/rfc/rfc9112#section-9.3) | Baseline: two clean pipelined GETs. Validates sequence test infrastructure against the target. |
| 26 | `SMUG-CL0-BODY-POISON` | Smuggling | [RFC 9112 §6.2](https://www.rfc-editor.org/rfc/rfc9112#section-6.2) | `Content-Length: 0` plus trailing bytes, then follow-up GET on same socket. Sequence telemetry for `0.CL`-style poisoning behavior. |
| 27 | `SMUG-GET-CL-BODY-DESYNC` | Smuggling | [RFC 9110 §9.3.1](https://www.rfc-editor.org/rfc/rfc9110#section-9.3.1) | "Content received in a GET request ... might lead some implementations to reject the request and close the connection because of its potential as a request smuggling attack." Adds follow-up desync check. |
| 28 | `SMUG-OPTIONS-CL-BODY-DESYNC` | Smuggling | [RFC 9110 §9.3.7](https://www.rfc-editor.org/rfc/rfc9110#section-9.3.7) | OPTIONS with body plus follow-up GET to detect unread-body poisoning on persistent connections. |
| 29 | `SMUG-EXPECT-100-CL-DESYNC` | Smuggling | [RFC 9110 §10.1.1](https://www.rfc-editor.org/rfc/rfc9110#section-10.1.1) | Expect/continue flow with immediate body plus follow-up GET; highlights whether connection framing remains synchronized. |

---

Expand All @@ -261,25 +272,25 @@ These tests don't map to a single RFC 2119 keyword but enforce defensive best pr

## Requirement Level by Suite

### Compliance Suite (74 tests)
### Compliance Suite (76 tests)

| Level | Tests |
|-------|-------|
| MUST | 45 |
| MUST | 47 |
| SHOULD | 15 |
| MAY | 6 |
| Unscored | 7 |
| N/A | 1 |

### Smuggling Suite (67 tests)
### Smuggling Suite (76 tests)

| Level | Tests |
|-------|-------|
| MUST | 39 |
| MUST | 44 |
| SHOULD | 9 |
| MAY | 3 |
| "ought to" | 1 |
| Unscored | 15 |
| Unscored | 19 |

### Malformed Input Suite (26 tests)

Expand Down Expand Up @@ -310,26 +321,26 @@ These tests don't map to a single RFC 2119 keyword but enforce defensive best pr
| RFC 9112 §3 | 9 | Request line, method, request-target |
| RFC 9112 §3.2 | 11 | Host header, request-target forms |
| RFC 9112 §5 | 7 | Header field syntax, sp-before-colon |
| RFC 9112 §5.2 | 2 | Obsolete line folding |
| RFC 9112 §5.2 | 3 | Obsolete line folding |
| RFC 9112 §6.1 | 21 | Transfer-Encoding, CL+TE ambiguity |
| RFC 9112 §6.2 | 4 | Content-Length body framing |
| RFC 9112 §6.2 | 5 | Content-Length body framing |
| RFC 9112 §6.3 | 5 | Message body length determination |
| RFC 9112 §7.1 | 15 | Chunked transfer coding format |
| RFC 9112 §7.1.1 | 4 | Chunk extensions |
| RFC 9112 §7.1 | 18 | Chunked transfer coding format |
| RFC 9112 §7.1.1 | 5 | Chunk extensions |
| RFC 9112 §7.1.2 | 1 | Chunked trailer section |
| RFC 9112 §9.3-9.6 | 3 | Connection management |
| RFC 9110 §5.3 | 1 | Header field duplication |
| RFC 9110 §5.4-5.6 | 8 | Field limits, values, lists, tokens |
| RFC 9110 §6.6.1 | 1 | Date header |
| RFC 9110 §7.2 | 1 | Host header semantics |
| RFC 9110 §7.8 | 4 | Upgrade |
| RFC 9110 §7.8 | 5 | Upgrade |
| RFC 9110 §8.3 | 1 | Content-Type |
| RFC 9110 §8.6 | 14 | Content-Length semantics |
| RFC 9110 §9.1-9.3 | 10 | Methods (GET, HEAD, CONNECT, OPTIONS, TRACE) |
| RFC 9110 §10.1.1 | 2 | Expect header |
| RFC 9110 §9.1-9.3 | 12 | Methods (GET, HEAD, CONNECT, OPTIONS, TRACE) |
| RFC 9110 §10.1.1 | 3 | Expect header |
| RFC 9110 §6.5 | 5 | Trailer field restrictions |
| RFC 9110 §12.5.1 | 1 | Content negotiation (Accept) |
| RFC 9110 §14.2 | 2 | Range requests |
| RFC 9110 §14.2 | 3 | Range requests |
| RFC 9110 §15.2 | 1 | 1xx status codes |
| RFC 9110 §15.5.6 | 1 | 405 Method Not Allowed |
| RFC 9110 §15.5.16 | 1 | 415 Unsupported Media Type |
Expand Down
9 changes: 9 additions & 0 deletions docs/content/docs/smuggling/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,19 +72,23 @@ For these, `400` is the strict/safe response and `2xx` is RFC-compliant. Http11P
{{< card link="te-not-final-chunked" title="TE-NOT-FINAL-CHUNKED" subtitle="Chunked is not the final transfer encoding." >}}
{{< card link="te-http10" title="TE-HTTP10" subtitle="Transfer-Encoding in HTTP/1.0 request." >}}
{{< card link="chunk-bare-semicolon" title="CHUNK-BARE-SEMICOLON" subtitle="Bare semicolon in chunk size." >}}
{{< card link="chunk-ext-invalid-token" title="CHUNK-EXT-INVALID-TOKEN" subtitle="Invalid token character in chunk extension name." >}}
{{< card link="bare-cr-header-value" title="BARE-CR-HEADER-VALUE" subtitle="Bare CR in header value." >}}
{{< card link="cl-octal" title="CL-OCTAL" subtitle="Content-Length with octal prefix." >}}
{{< card link="chunk-underscore" title="CHUNK-UNDERSCORE" subtitle="Underscore in chunk size." >}}
{{< card link="te-empty-value" title="TE-EMPTY-VALUE" subtitle="Empty Transfer-Encoding value with CL." >}}
{{< card link="te-leading-comma" title="TE-LEADING-COMMA" subtitle="Leading comma in Transfer-Encoding." >}}
{{< card link="te-duplicate-headers" title="TE-DUPLICATE-HEADERS" subtitle="Two TE headers with conflicting values." >}}
{{< card link="chunk-hex-prefix" title="CHUNK-HEX-PREFIX" subtitle="Chunk size with 0x prefix." >}}
{{< card link="chunk-size-plus" title="CHUNK-SIZE-PLUS" subtitle="Chunk size with leading plus sign." >}}
{{< card link="chunk-size-trailing-ows" title="CHUNK-SIZE-TRAILING-OWS" subtitle="Chunk size with trailing whitespace." >}}
{{< card link="cl-hex-prefix" title="CL-HEX-PREFIX" subtitle="Content-Length with 0x prefix." >}}
{{< card link="cl-internal-space" title="CL-INTERNAL-SPACE" subtitle="Space inside Content-Length value." >}}
{{< card link="chunk-leading-sp" title="CHUNK-LEADING-SP" subtitle="Leading space in chunk size." >}}
{{< card link="chunk-missing-trailing-crlf" title="CHUNK-MISSING-TRAILING-CRLF" subtitle="Chunk data without trailing CRLF." >}}
{{< card link="chunk-ext-lf" title="CHUNK-EXT-LF" subtitle="Bare LF in chunk extension (TERM.EXT vector)." >}}
{{< card link="chunk-spill" title="CHUNK-SPILL" subtitle="Chunk declares size 5 but sends 7 bytes." >}}
{{< card link="chunk-invalid-size-desync" title="CHUNK-INVALID-SIZE-DESYNC" subtitle="Invalid chunk size plus poison-byte follow-up check." >}}
{{< card link="chunk-lf-term" title="CHUNK-LF-TERM" subtitle="Bare LF as chunk data terminator." >}}
{{< card link="chunk-ext-ctrl" title="CHUNK-EXT-CTRL" subtitle="NUL byte in chunk extension." >}}
{{< card link="chunk-ext-cr" title="CHUNK-EXT-CR" subtitle="Bare CR inside chunk extension metadata." >}}
Expand All @@ -100,6 +104,7 @@ For these, `400` is the strict/safe response and `2xx` is RFC-compliant. Http11P
{{< card link="cl-double-zero" title="CL-DOUBLE-ZERO" subtitle="Content-Length: 00 — leading zero ambiguity." >}}
{{< card link="cl-leading-zeros-octal" title="CL-LEADING-ZEROS-OCTAL" subtitle="Content-Length: 0200 — octal vs decimal disagreement." >}}
{{< card link="te-obs-fold" title="TE-OBS-FOLD" subtitle="Transfer-Encoding with obs-fold line wrapping." >}}
{{< card link="options-te-obs-fold" title="OPTIONS-TE-OBS-FOLD" subtitle="OPTIONS path for TE obs-fold plus follow-up close check." >}}
{{< card link="te-trailing-comma" title="TE-TRAILING-COMMA" subtitle="Transfer-Encoding: chunked, — trailing comma." >}}
{{< card link="multiple-host-comma" title="MULTIPLE-HOST-COMMA" subtitle="Host with comma-separated values." >}}
{{< /cards >}}
Expand All @@ -116,13 +121,17 @@ For these, `400` is the strict/safe response and `2xx` is RFC-compliant. Http11P
{{< card link="cl-comma-triple" title="CL-COMMA-TRIPLE" subtitle="Three comma-separated identical CL values." >}}
{{< card link="chunked-with-params" title="CHUNKED-WITH-PARAMS" subtitle="Parameters on chunked encoding." >}}
{{< card link="expect-100-cl" title="EXPECT-100-CL" subtitle="Expect: 100-continue with Content-Length." >}}
{{< card link="expect-100-cl-desync" title="EXPECT-100-CL-DESYNC" subtitle="Expect workflow with follow-up desync check." >}}
{{< card link="trailer-cl" title="TRAILER-CL" subtitle="Content-Length in chunked trailers (prohibited)." >}}
{{< card link="trailer-te" title="TRAILER-TE" subtitle="Transfer-Encoding in chunked trailers (prohibited)." >}}
{{< card link="trailer-host" title="TRAILER-HOST" subtitle="Host header in chunked trailers (must not route)." >}}
{{< card link="trailer-auth" title="TRAILER-AUTH" subtitle="Authorization in chunked trailers (prohibited)." >}}
{{< card link="trailer-content-type" title="TRAILER-CONTENT-TYPE" subtitle="Content-Type in chunked trailers (prohibited)." >}}
{{< card link="cl0-body-poison" title="CL0-BODY-POISON" subtitle="CL:0 with trailing byte and follow-up request." >}}
{{< card link="get-cl-body-desync" title="GET-CL-BODY-DESYNC" subtitle="GET with body plus follow-up desync check." >}}
{{< card link="head-cl-body" title="HEAD-CL-BODY" subtitle="HEAD with Content-Length and body." >}}
{{< card link="options-cl-body" title="OPTIONS-CL-BODY" subtitle="OPTIONS with Content-Length and body." >}}
{{< card link="options-cl-body-desync" title="OPTIONS-CL-BODY-DESYNC" subtitle="OPTIONS with body plus follow-up desync check." >}}
{{< card link="te-tab-before-value" title="TE-TAB-BEFORE-VALUE" subtitle="Tab as OWS before Transfer-Encoding value." >}}
{{< card link="absolute-uri-host-mismatch" title="ABSOLUTE-URI-HOST-MISMATCH" subtitle="Absolute-form URI with different Host header." >}}
{{< /cards >}}
46 changes: 46 additions & 0 deletions docs/content/docs/smuggling/chunk-ext-invalid-token.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
title: "CHUNK-EXT-INVALID-TOKEN"
description: "SMUG-CHUNK-EXT-INVALID-TOKEN test documentation"
weight: 1
---

| | |
|---|---|
| **Test ID** | `SMUG-CHUNK-EXT-INVALID-TOKEN` |
| **Category** | Smuggling |
| **RFC** | [RFC 9112 §7.1.1](https://www.rfc-editor.org/rfc/rfc9112#section-7.1.1) |
| **Requirement** | Implicit MUST (grammar violation) |
| **Expected** | `400` or close |

## What it sends

A chunk extension with an invalid token character in the extension name (`bad[`):

```http
POST / HTTP/1.1\r\n
Host: localhost:8080\r\n
Transfer-Encoding: chunked\r\n
\r\n
5;bad[=x\r\n
hello\r\n
0\r\n
\r\n
```

## What the RFC says

> "chunk-ext-name = token" -- RFC 9112 Section 7.1.1

`[` is not a valid token character, so the extension syntax is invalid.

## Partial Coverage Note

Existing tests already cover malformed chunk extensions (`SMUG-CHUNK-BARE-SEMICOLON`, `SMUG-CHUNK-EXT-CTRL`, `SMUG-CHUNK-EXT-CR`, `SMUG-CHUNK-EXT-LF`). This case specifically targets invalid token characters in extension names.

## Why it matters

Different extension parsers may tokenize this differently, creating front-end/back-end framing inconsistencies.

## Sources

- [RFC 9112 §7.1.1](https://www.rfc-editor.org/rfc/rfc9112#section-7.1.1)
49 changes: 49 additions & 0 deletions docs/content/docs/smuggling/chunk-invalid-size-desync.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
title: "CHUNK-INVALID-SIZE-DESYNC"
description: "SMUG-CHUNK-INVALID-SIZE-DESYNC test documentation"
weight: 1
---

| | |
|---|---|
| **Test ID** | `SMUG-CHUNK-INVALID-SIZE-DESYNC` |
| **Category** | Smuggling |
| **RFC** | [RFC 9112 §7.1](https://www.rfc-editor.org/rfc/rfc9112#section-7.1) |
| **Requirement** | MUST |
| **Expected** | `400` or close |

## What it sends

A two-step sequence: invalid chunk-size `+0` with poison byte `X`, then a clean `GET`.

```http
POST / HTTP/1.1\r\n
Host: localhost:8080\r\n
Transfer-Encoding: chunked\r\n
\r\n
+0\r\n
\r\n
X

GET / HTTP/1.1\r\n
Host: localhost:8080\r\n
\r\n
```

## What the RFC says

> "chunk-size = 1*HEXDIG" -- RFC 9112 Section 7.1

Invalid chunk-size is a framing error. This sequence confirms whether acceptance leads to follow-up parsing corruption.

## Partial Coverage Note

Existing tests (`SMUG-CHUNK-NEGATIVE`, `SMUG-CHUNK-HEX-PREFIX`, `SMUG-CHUNK-SPILL`, `MAL-CHUNK-SIZE-OVERFLOW`) cover invalid chunk primitives. This test adds explicit desync confirmation via a follow-up request.

## Why it matters

If invalid chunk-size is tolerated and the connection remains open, poison bytes can be interpreted as the next request.

## Sources

- [RFC 9112 §7.1](https://www.rfc-editor.org/rfc/rfc9112#section-7.1)
42 changes: 42 additions & 0 deletions docs/content/docs/smuggling/chunk-size-plus.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
title: "CHUNK-SIZE-PLUS"
description: "SMUG-CHUNK-SIZE-PLUS test documentation"
weight: 1
---

| | |
|---|---|
| **Test ID** | `SMUG-CHUNK-SIZE-PLUS` |
| **Category** | Smuggling |
| **RFC** | [RFC 9112 §7.1](https://www.rfc-editor.org/rfc/rfc9112#section-7.1) |
| **Requirement** | Implicit MUST (grammar violation) |
| **Expected** | `400` or close |

## What it sends

A chunked request where chunk-size is prefixed by `+`.

```http
POST / HTTP/1.1\r\n
Host: localhost:8080\r\n
Transfer-Encoding: chunked\r\n
\r\n
+5\r\n
hello\r\n
0\r\n
\r\n
```

## What the RFC says

> "chunk-size = 1*HEXDIG" -- RFC 9112 Section 7.1

The plus sign is not a hexadecimal digit. The chunk-size token is invalid.

## Why it matters

Lenient numeric parsing (`+5`) in one component and strict parsing in another creates parser disagreement and desync opportunities.

## Sources

- [RFC 9112 §7.1](https://www.rfc-editor.org/rfc/rfc9112#section-7.1)
Loading
Loading