Skip to content

Commit f06b473

Browse files
committed
Cokies suite
1 parent d082174 commit f06b473

20 files changed

Lines changed: 1156 additions & 5 deletions

File tree

docs/content/cookies/_index.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
---
2+
title: Cookies
3+
layout: wide
4+
toc: false
5+
---
6+
7+
## Cookie Handling
8+
9+
These tests check how servers and frameworks handle adversarial `Cookie` headers. Cookie parsing is done at the framework level, not by application code, so malformed cookies can crash parsers or produce mangled values before your code ever runs. All cookie tests are **unscored** since cookies are governed by RFC 6265, not RFC 9110/9112.
10+
11+
<style>h1.hx\:mt-2{display:none}.probe-hint{background:#ddf4ff;border:1px solid #54aeff;border-radius:6px;padding:10px 14px;font-size:13px;color:#0969da;font-weight:500}html.dark .probe-hint{background:#1c2333;border-color:#1f6feb;color:#58a6ff}</style>
12+
<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-bottom:16px;">
13+
<div class="probe-hint"><strong style="font-size:14px;">Server Name</strong><br>Click to view Dockerfile and source code</div>
14+
<div class="probe-hint"><strong style="font-size:14px;">Table Row</strong><br>Click to expand all results for that server</div>
15+
<div class="probe-hint"><strong style="font-size:14px;">Result Cell</strong><br>Click to see the full HTTP request and response</div>
16+
</div>
17+
18+
<div class="probe-filters">
19+
<div id="lang-filter"></div>
20+
<div id="method-filter"></div>
21+
<div id="rfc-level-filter"></div>
22+
</div>
23+
<div id="table-cookies"><p><em>Loading...</em></p></div>
24+
25+
<script src="/Http11Probe/probe/data.js"></script>
26+
<script src="/Http11Probe/probe/render.js"></script>
27+
<script>
28+
(function () {
29+
if (!window.PROBE_DATA) {
30+
document.getElementById('table-cookies').innerHTML = '<p><em>No probe data available yet. Run the Probe workflow manually on <code>main</code> to generate results.</em></p>';
31+
return;
32+
}
33+
var GROUPS = [
34+
{ key: 'echo', label: 'Echo-Based (Survivability)', testIds: [
35+
'COOK-ECHO','COOK-OVERSIZED','COOK-EMPTY','COOK-NUL',
36+
'COOK-CONTROL-CHARS','COOK-MANY-PAIRS','COOK-MALFORMED','COOK-MULTI-HEADER'
37+
]},
38+
{ key: 'parsed', label: 'Parsed Cookies (Framework Parser)', testIds: [
39+
'COOK-PARSED-BASIC','COOK-PARSED-MULTI','COOK-PARSED-EMPTY-VAL','COOK-PARSED-SPECIAL'
40+
]}
41+
];
42+
43+
var ALL_IDS = [];
44+
GROUPS.forEach(function (g) { g.testIds.forEach(function (tid) { ALL_IDS.push(tid); }); });
45+
46+
var langData = window.PROBE_DATA;
47+
var methodFilter = null;
48+
var rfcLevelFilter = null;
49+
50+
function rerender() {
51+
var data = langData;
52+
if (methodFilter) data = ProbeRender.filterByMethod(data, methodFilter);
53+
if (rfcLevelFilter) data = ProbeRender.filterByRfcLevel(data, rfcLevelFilter);
54+
var ctx = ProbeRender.buildLookups(data.servers);
55+
ctx.testIds = ALL_IDS;
56+
ProbeRender.renderSubTables('table-cookies', 'Cookies', ctx, GROUPS);
57+
}
58+
rerender();
59+
var catData = ProbeRender.filterByCategory(window.PROBE_DATA, ['Cookies']);
60+
ProbeRender.renderLanguageFilter('lang-filter', window.PROBE_DATA, function (d) { langData = d; rerender(); });
61+
ProbeRender.renderMethodFilter('method-filter', catData, function (m) { methodFilter = m; rerender(); });
62+
ProbeRender.renderRfcLevelFilter('rfc-level-filter', catData, function (l) { rfcLevelFilter = l; rerender(); });
63+
})();
64+
</script>
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
---
2+
title: Cookies
3+
description: "Cookies — Http11Probe documentation"
4+
weight: 13
5+
sidebar:
6+
open: false
7+
---
8+
9+
Cookie parsing is handled by framework-level parsers that run automatically on every request. Malformed `Cookie` headers can crash these parsers, cause memory issues, or produce mangled values. These tests check whether servers and frameworks survive adversarial cookie input.
10+
11+
Cookies are defined by [RFC 6265](https://www.rfc-editor.org/rfc/rfc6265) (not RFC 9110/9112), so all tests are **unscored**.
12+
13+
## Scoring
14+
15+
All cookie tests are **unscored**:
16+
17+
- **Pass** — Server handled the cookie input safely
18+
- **Warn** — Endpoint not available or non-ideal but non-dangerous behavior
19+
- **Fail** — Server crashed (500), preserved dangerous bytes, or lost data it should have parsed
20+
21+
## Echo-Based Tests
22+
23+
These tests target `/echo` and work on all servers. They check whether the server survives adversarial cookie headers without crashing.
24+
25+
{{< cards >}}
26+
{{< card link="echo" title="ECHO" subtitle="Basic Cookie header echoed back." >}}
27+
{{< card link="oversized" title="OVERSIZED" subtitle="64KB Cookie header." >}}
28+
{{< card link="empty" title="EMPTY" subtitle="Empty Cookie header value." >}}
29+
{{< card link="nul" title="NUL" subtitle="NUL byte in cookie value." >}}
30+
{{< card link="control-chars" title="CONTROL-CHARS" subtitle="Control characters in cookie value." >}}
31+
{{< card link="many-pairs" title="MANY-PAIRS" subtitle="1000 cookie key=value pairs." >}}
32+
{{< card link="malformed" title="MALFORMED" subtitle="Completely malformed cookie syntax." >}}
33+
{{< card link="multi-header" title="MULTI-HEADER" subtitle="Two separate Cookie headers." >}}
34+
{{< /cards >}}
35+
36+
## Parsed-Cookie Tests
37+
38+
These tests target `/cookie` and check whether the framework's cookie parser correctly extracts key=value pairs. Servers without a `/cookie` endpoint return 404 (Warn).
39+
40+
{{< cards >}}
41+
{{< card link="parsed-basic" title="PARSED-BASIC" subtitle="Single foo=bar cookie parsed." >}}
42+
{{< card link="parsed-multi" title="PARSED-MULTI" subtitle="Three cookies parsed from one header." >}}
43+
{{< card link="parsed-empty-val" title="PARSED-EMPTY-VAL" subtitle="Cookie with empty value." >}}
44+
{{< card link="parsed-special" title="PARSED-SPECIAL" subtitle="Spaces and = in cookie values." >}}
45+
{{< /cards >}}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
---
2+
title: "CONTROL-CHARS"
3+
description: "COOK-CONTROL-CHARS test documentation"
4+
weight: 5
5+
---
6+
7+
| | |
8+
|---|---|
9+
| **Test ID** | `COOK-CONTROL-CHARS` |
10+
| **Category** | Cookies |
11+
| **Scored** | No |
12+
| **Expected** | `400` (rejected) or `2xx` without control chars |
13+
14+
## What it sends
15+
16+
```http
17+
GET /echo HTTP/1.1\r\n
18+
Host: localhost:8080\r\n
19+
Cookie: foo=\x01\x02\x03\r\n
20+
\r\n
21+
```
22+
23+
A `Cookie` header containing control characters SOH (`0x01`), STX (`0x02`), and ETX (`0x03`) as the cookie value.
24+
25+
## What the RFC says
26+
27+
> "cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E" — RFC 6265 §4.1.1
28+
29+
Control characters (`0x00-0x1F`) are explicitly excluded from the `cookie-octet` production. They are not valid in cookie values.
30+
31+
## Why it matters
32+
33+
Control characters in cookie values can cause:
34+
- **Log injection** — if the bytes reach log files, they may corrupt formatting or inject terminal escape sequences
35+
- **Parser confusion** — some parsers may interpret control characters as delimiters
36+
- **Security filter bypass** — WAFs may not inspect or sanitize non-printable bytes
37+
38+
## Verdicts
39+
40+
- **Pass**`400` (rejected) or `2xx` with control characters stripped/cookie dropped
41+
- **Fail**`2xx` with control characters preserved in the response body
42+
43+
## Sources
44+
45+
- [RFC 6265 §4.1.1](https://www.rfc-editor.org/rfc/rfc6265#section-4.1.1) — cookie-octet definition

docs/content/docs/cookies/echo.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
title: "ECHO"
3+
description: "COOK-ECHO test documentation"
4+
weight: 1
5+
---
6+
7+
| | |
8+
|---|---|
9+
| **Test ID** | `COOK-ECHO` |
10+
| **Category** | Cookies |
11+
| **Scored** | No |
12+
| **Expected** | `2xx` with `Cookie:` in echo body |
13+
14+
## What it sends
15+
16+
```http
17+
GET /echo HTTP/1.1\r\n
18+
Host: localhost:8080\r\n
19+
Cookie: foo=bar\r\n
20+
\r\n
21+
```
22+
23+
A standard request with a simple, valid `Cookie` header targeting the `/echo` endpoint.
24+
25+
## What the RFC says
26+
27+
> "When the user agent generates an HTTP request, the user agent MUST NOT attach more than one header field named Cookie." — RFC 6265 §5.4
28+
29+
This test sends a single, well-formed `Cookie` header. It serves as a baseline to confirm the echo endpoint reflects cookie headers.
30+
31+
## Why it matters
32+
33+
This is the baseline cookie test. If the server cannot echo back a simple `Cookie: foo=bar` header, all other cookie tests are meaningless.
34+
35+
## Verdicts
36+
37+
- **Pass** — 2xx response with `Cookie:` visible in the echo body
38+
- **Fail** — No response, or 2xx without the cookie header in the body
39+
40+
## Sources
41+
42+
- [RFC 6265 §5.4](https://www.rfc-editor.org/rfc/rfc6265#section-5.4) — sending cookies

docs/content/docs/cookies/empty.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
title: "EMPTY"
3+
description: "COOK-EMPTY test documentation"
4+
weight: 3
5+
---
6+
7+
| | |
8+
|---|---|
9+
| **Test ID** | `COOK-EMPTY` |
10+
| **Category** | Cookies |
11+
| **Scored** | No |
12+
| **Expected** | `2xx` or `400` |
13+
14+
## What it sends
15+
16+
```http
17+
GET /echo HTTP/1.1\r\n
18+
Host: localhost:8080\r\n
19+
Cookie: \r\n
20+
\r\n
21+
```
22+
23+
A `Cookie` header with an empty value (nothing after the colon and space).
24+
25+
## What the RFC says
26+
27+
> "cookie-header = 'Cookie:' OWS cookie-string OWS" — RFC 6265 §4.2
28+
29+
An empty cookie-string does not match `cookie-pair *( ";" SP cookie-pair )` since `cookie-pair` requires at least a name. However, servers should handle this gracefully.
30+
31+
## Why it matters
32+
33+
Empty `Cookie` headers can trigger null-pointer dereferences or empty-string edge cases in cookie parsers. The test verifies the server doesn't crash.
34+
35+
## Verdicts
36+
37+
- **Pass**`2xx` (accepted) or `400` (rejected gracefully)
38+
- **Fail**`500` or connection crash
39+
40+
## Sources
41+
42+
- [RFC 6265 §4.2](https://www.rfc-editor.org/rfc/rfc6265#section-4.2) — cookie header syntax
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
---
2+
title: "MALFORMED"
3+
description: "COOK-MALFORMED test documentation"
4+
weight: 7
5+
---
6+
7+
| | |
8+
|---|---|
9+
| **Test ID** | `COOK-MALFORMED` |
10+
| **Category** | Cookies |
11+
| **Scored** | No |
12+
| **Expected** | `2xx` or `400` |
13+
14+
## What it sends
15+
16+
```http
17+
GET /echo HTTP/1.1\r\n
18+
Host: localhost:8080\r\n
19+
Cookie: ===;;;\r\n
20+
\r\n
21+
```
22+
23+
A `Cookie` header with completely invalid syntax — no valid cookie-name, only equals signs and semicolons.
24+
25+
## What the RFC says
26+
27+
> "cookie-pair = cookie-name '=' cookie-value" — RFC 6265 §4.1.1
28+
29+
> "cookie-name = token" — RFC 6265 §4.1.1
30+
31+
The value `===;;;` does not match the `cookie-pair` grammar. There is no valid `cookie-name` (an empty name before the first `=` is not a valid token).
32+
33+
## Why it matters
34+
35+
Framework cookie parsers must handle completely malformed cookie strings gracefully. This tests the worst-case scenario for parser resilience — the value bears no resemblance to valid cookie syntax.
36+
37+
## Verdicts
38+
39+
- **Pass**`2xx` (survived) or `400` (rejected gracefully)
40+
- **Fail**`500` or connection crash
41+
42+
## Sources
43+
44+
- [RFC 6265 §4.1.1](https://www.rfc-editor.org/rfc/rfc6265#section-4.1.1) — cookie-pair syntax
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
---
2+
title: "MANY-PAIRS"
3+
description: "COOK-MANY-PAIRS test documentation"
4+
weight: 6
5+
---
6+
7+
| | |
8+
|---|---|
9+
| **Test ID** | `COOK-MANY-PAIRS` |
10+
| **Category** | Cookies |
11+
| **Scored** | No |
12+
| **Expected** | `2xx` or `400`/`431` |
13+
14+
## What it sends
15+
16+
```http
17+
GET /echo HTTP/1.1\r\n
18+
Host: localhost:8080\r\n
19+
Cookie: k0=v0; k1=v1; k2=v2; ... ; k999=v999\r\n
20+
\r\n
21+
```
22+
23+
A `Cookie` header containing 1000 semicolon-separated key=value pairs.
24+
25+
## What the RFC says
26+
27+
> "At least 50 cookies per domain." — RFC 6265 §6.1
28+
29+
The practical limit of 50 cookies per domain is a user-agent guideline. Servers have no mandated limit, but 1000 pairs in a single header tests parser performance boundaries.
30+
31+
## Why it matters
32+
33+
Each cookie pair must be parsed, allocated, and stored in internal data structures. 1000 pairs can trigger:
34+
- **O(n) or O(n^2) parsing** in naive cookie parsers
35+
- **Memory exhaustion** from 1000 individual allocations
36+
- **Hash table collisions** in cookie lookup structures
37+
38+
A well-behaved server should either parse all 1000 pairs or reject the oversized header.
39+
40+
## Verdicts
41+
42+
- **Pass**`2xx` (survived) or `400`/`431` (rejected gracefully)
43+
- **Fail**`500` or connection crash
44+
45+
## Sources
46+
47+
- [RFC 6265 §6.1](https://www.rfc-editor.org/rfc/rfc6265#section-6.1) — cookie limits
48+
- [RFC 6585 §5](https://www.rfc-editor.org/rfc/rfc6585#section-5) — 431 status code
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
---
2+
title: "MULTI-HEADER"
3+
description: "COOK-MULTI-HEADER test documentation"
4+
weight: 8
5+
---
6+
7+
| | |
8+
|---|---|
9+
| **Test ID** | `COOK-MULTI-HEADER` |
10+
| **Category** | Cookies |
11+
| **Scored** | No |
12+
| **Expected** | `2xx` with both cookies |
13+
14+
## What it sends
15+
16+
```http
17+
GET /echo HTTP/1.1\r\n
18+
Host: localhost:8080\r\n
19+
Cookie: a=1\r\n
20+
Cookie: b=2\r\n
21+
\r\n
22+
```
23+
24+
Two separate `Cookie` header lines in the same request.
25+
26+
## What the RFC says
27+
28+
> "If the user agent does attach a Cookie header field to an HTTP request, the user agent MUST NOT attach more than one header field named Cookie." — RFC 6265 §5.4
29+
30+
> "If a server receives multiple Cookie header field lines in a single request... the server SHOULD treat them as if they had been sent as a single cookie-string separated by semicolons." — RFC 6265 §5.3 (revised in RFC 6265bis)
31+
32+
While clients MUST NOT send multiple Cookie headers, servers should handle them gracefully by folding them together.
33+
34+
## Why it matters
35+
36+
Multiple `Cookie` headers can occur in practice through proxy manipulation or misconfigured middleware. A server that crashes or drops cookies when it sees duplicates is fragile. The ideal behavior is to fold them into a single cookie-string as RFC 6265bis recommends.
37+
38+
## Verdicts
39+
40+
- **Pass**`2xx` with both `a=1` and `b=2` in the echo body
41+
- **Warn** — Only one cookie echoed, or `400` (rejected but didn't crash)
42+
- **Fail**`500` or connection crash
43+
44+
## Sources
45+
46+
- [RFC 6265 §5.4](https://www.rfc-editor.org/rfc/rfc6265#section-5.4) — sending cookies
47+
- [RFC 6265 §5.3](https://www.rfc-editor.org/rfc/rfc6265#section-5.3) — cookie processing

0 commit comments

Comments
 (0)