Skip to content

Commit 4483655

Browse files
MDA2AVclaude
andcommitted
Add separate pages for Compliance, Smuggling, Malformed Input, Glossary
- Each category gets its own nav tab and dedicated page with explanation - Glossary page explains RFCs, smuggling mechanics with CL.TE/TE.CL examples - Shared render.js extracted to avoid JS duplication across pages - Home page cards link to individual category pages - Probe icon logo added Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 015d612 commit 4483655

9 files changed

Lines changed: 450 additions & 186 deletions

File tree

docs/content/_index.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ layout: hextra-home
2727
## Features
2828

2929
{{< cards >}}
30-
{{< card link="probe-results" title="Compliance Testing" subtitle="RFC 9110/9112 protocol requirements — bare LF, obs-fold, missing Host, invalid versions, and more." icon="check-circle" >}}
31-
{{< card link="probe-results" title="Smuggling Detection" subtitle="CL/TE ambiguity, duplicate Content-Length, leading zeros, pipeline probes, and obfuscation vectors." icon="shield-exclamation" >}}
32-
{{< card link="probe-results" title="Robustness Testing" subtitle="Binary garbage, oversized URLs/headers, control characters, integer overflow, and incomplete requests." icon="lightning-bolt" >}}
30+
{{< card link="compliance" title="Compliance Testing" subtitle="RFC 9110/9112 protocol requirements — bare LF, obs-fold, missing Host, invalid versions, and more." icon="check-circle" >}}
31+
{{< card link="smuggling" title="Smuggling Detection" subtitle="CL/TE ambiguity, duplicate Content-Length, leading zeros, pipeline probes, and obfuscation vectors." icon="shield-exclamation" >}}
32+
{{< card link="malformed-input" title="Robustness Testing" subtitle="Binary garbage, oversized URLs/headers, control characters, integer overflow, and incomplete requests." icon="lightning-bolt" >}}
3333
{{< /cards >}}

docs/content/compliance/_index.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
---
2+
title: Compliance
3+
layout: wide
4+
toc: false
5+
---
6+
7+
## RFC 9110/9112 Compliance
8+
9+
These tests validate that HTTP/1.1 servers correctly implement the protocol requirements defined in [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110) (HTTP Semantics) and [RFC 9112](https://www.rfc-editor.org/rfc/rfc9112) (HTTP/1.1 Message Syntax and Routing).
10+
11+
Each test sends a request that violates a specific **MUST** or **MUST NOT** requirement from the RFCs. A compliant server should reject these with a `400 Bad Request` (or close the connection). Accepting the request silently means the server is non-compliant and potentially vulnerable to downstream attacks.
12+
13+
**What's tested:**
14+
- **Line endings** &mdash; bare `LF` without `CR`, `CR` without `LF` (RFC 9112 &sect;2.2)
15+
- **Request-line format** &mdash; multiple spaces, missing target, fragments in URI (RFC 9112 &sect;3)
16+
- **HTTP version** &mdash; invalid version strings, HTTP/0.9 requests (RFC 9112 &sect;2.3)
17+
- **Header syntax** &mdash; obs-fold, space before colon, empty names, invalid characters, missing colon (RFC 9112 &sect;5, RFC 9110 &sect;5.6.2)
18+
- **Host header** &mdash; missing or duplicate Host with conflicting values (RFC 9112 &sect;7.1, RFC 9110 &sect;5.4)
19+
- **Content-Length** &mdash; non-numeric, plus sign, overflow (RFC 9112 &sect;6.1)
20+
21+
<div id="table-compliance"><p><em>Loading...</em></p></div>
22+
23+
<script src="/Http11Probe/probe/data.js"></script>
24+
<script src="/Http11Probe/probe/render.js"></script>
25+
<script>
26+
(function () {
27+
if (!window.PROBE_DATA) {
28+
document.getElementById('table-compliance').innerHTML = '<p><em>No probe data available yet. Run the Probe workflow manually on <code>main</code> to generate results.</em></p>';
29+
return;
30+
}
31+
var ctx = ProbeRender.buildLookups(window.PROBE_DATA.servers);
32+
ProbeRender.renderTable('table-compliance', 'Compliance', ctx);
33+
})();
34+
</script>

docs/content/glossary/_index.md

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
---
2+
title: Glossary
3+
layout: wide
4+
toc: true
5+
---
6+
7+
## What is an RFC?
8+
9+
An **RFC** (Request for Comments) is a formal document published by the [Internet Engineering Task Force (IETF)](https://www.ietf.org/) that defines the standards and protocols that power the internet. Despite the informal-sounding name, RFCs are the authoritative specifications that all implementations must follow for interoperability.
10+
11+
HTTP/1.1 is defined by two key RFCs:
12+
13+
- **[RFC 9110](https://www.rfc-editor.org/rfc/rfc9110)** &mdash; *HTTP Semantics*. Defines the meaning of HTTP methods, status codes, headers, and content negotiation. This is the "what" of HTTP.
14+
- **[RFC 9112](https://www.rfc-editor.org/rfc/rfc9112)** &mdash; *HTTP/1.1 Message Syntax and Routing*. Defines the wire format: how requests and responses are framed as bytes on a TCP connection. This is the "how" of HTTP/1.1.
15+
16+
RFCs use specific keywords defined in [RFC 2119](https://www.rfc-editor.org/rfc/rfc2119):
17+
18+
| Keyword | Meaning |
19+
|---------|---------|
20+
| **MUST** | Absolute requirement. Violating this means the implementation is non-compliant. |
21+
| **MUST NOT** | Absolute prohibition. |
22+
| **SHOULD** | Recommended but there may be valid reasons to deviate in particular circumstances. |
23+
| **MAY** | Optional behavior. |
24+
25+
When a test in Http11Probe references `RFC 9112 &sect;5.1`, it means the test validates a specific requirement from section 5.1 of that document.
26+
27+
## What is HTTP Request Smuggling?
28+
29+
HTTP request smuggling is an attack that exploits disagreements between HTTP processors about where one request ends and the next begins in a TCP byte stream.
30+
31+
### How it works
32+
33+
In a typical web architecture, requests flow through multiple layers:
34+
35+
```
36+
Client --> CDN / Load Balancer --> Application Server
37+
(front-end) (back-end)
38+
```
39+
40+
Both the front-end and back-end must parse the HTTP stream to determine request boundaries. HTTP/1.1 provides two mechanisms for this:
41+
42+
1. **Content-Length** &mdash; an explicit byte count of the body
43+
2. **Transfer-Encoding: chunked** &mdash; the body is sent in length-prefixed chunks
44+
45+
When a request contains **both** headers, or contains them in ambiguous forms, different servers may disagree on the body length. This disagreement lets an attacker hide a second request inside the body of the first.
46+
47+
### CL.TE Smuggling Example
48+
49+
The attacker sends a request where the front-end uses `Content-Length` and the back-end uses `Transfer-Encoding`:
50+
51+
```http
52+
POST / HTTP/1.1
53+
Host: example.com
54+
Content-Length: 13
55+
Transfer-Encoding: chunked
56+
57+
0\r\n
58+
\r\n
59+
SMUGGLED
60+
```
61+
62+
**Front-end** (reads Content-Length: 13): sees 13 bytes of body (`0\r\n\r\nSMUGGLED`), forwards the whole thing as one request.
63+
64+
**Back-end** (reads Transfer-Encoding: chunked): reads chunk size `0`, which signals end-of-body. The remaining bytes (`SMUGGLED`) are left in the TCP buffer and interpreted as the **start of the next request**.
65+
66+
The attacker has now injected a request that bypasses the front-end entirely.
67+
68+
### TE.CL Smuggling Example
69+
70+
The reverse: the front-end uses `Transfer-Encoding` and the back-end uses `Content-Length`:
71+
72+
```http
73+
POST / HTTP/1.1
74+
Host: example.com
75+
Content-Length: 3
76+
Transfer-Encoding: chunked
77+
78+
8\r\n
79+
SMUGGLED\r\n
80+
0\r\n
81+
\r\n
82+
```
83+
84+
**Front-end** (chunked): reads chunk of size 8 (`SMUGGLED`), then chunk of size 0 (end). Forwards everything.
85+
86+
**Back-end** (Content-Length: 3): reads only 3 bytes of body (`8\r\n`). The rest (`SMUGGLED\r\n0\r\n\r\n`) becomes the next request.
87+
88+
### Why servers must reject ambiguous requests
89+
90+
The only safe behavior is to **reject** any request with ambiguous framing:
91+
92+
- Both `Content-Length` and `Transfer-Encoding` present &rarr; **400**
93+
- Duplicate `Content-Length` with different values &rarr; **400**
94+
- Obfuscated `Transfer-Encoding` (e.g. `xchunked`, `chunked `) &rarr; **400**
95+
96+
A server that "guesses" which header to use is a smuggling vector waiting to happen.
97+
98+
### Real-world impact
99+
100+
HTTP smuggling has been used to:
101+
- **Bypass authentication** &mdash; smuggle requests that skip WAF/auth layers
102+
- **Poison web caches** &mdash; inject responses that get cached and served to other users
103+
- **Hijack sessions** &mdash; prepend attacker-controlled headers to other users' requests
104+
- **Exfiltrate data** &mdash; redirect internal responses to attacker-controlled endpoints
105+
106+
## Test Definitions
107+
108+
Every test ID links back here from the result tables. Click a test name in any results table to jump to its definition.
109+
110+
<div id="glossary-tests"><p><em>Loading...</em></p></div>
111+
112+
<script src="/Http11Probe/probe/data.js"></script>
113+
<script src="/Http11Probe/probe/render.js"></script>
114+
<script>
115+
(function () {
116+
if (!window.PROBE_DATA) {
117+
document.getElementById('glossary-tests').innerHTML = '<p><em>No probe data available yet.</em></p>';
118+
return;
119+
}
120+
var ctx = ProbeRender.buildLookups(window.PROBE_DATA.servers);
121+
var names = ctx.names, lookup = ctx.lookup, testIds = ctx.testIds;
122+
123+
var categories = [
124+
{ key: 'Compliance', title: 'Compliance Tests' },
125+
{ key: 'Smuggling', title: 'Smuggling Tests' },
126+
{ key: 'MalformedInput', title: 'Malformed Input Tests' }
127+
];
128+
129+
var html = '';
130+
categories.forEach(function (cat) {
131+
var tests = testIds.filter(function (tid) {
132+
return lookup[names[0]][tid] && lookup[names[0]][tid].category === cat.key;
133+
});
134+
if (tests.length === 0) return;
135+
136+
var scored = tests.filter(function (tid) { return lookup[names[0]][tid].scored !== false; });
137+
var unscored = tests.filter(function (tid) { return lookup[names[0]][tid].scored === false; });
138+
139+
html += '<h3>' + cat.title + '</h3>';
140+
html += '<div style="margin-bottom:1.5rem;">';
141+
142+
function row(tid) {
143+
var r = lookup[names[0]][tid];
144+
if (!r) return '';
145+
var rfc = r.rfc ? ' <span style="color:#656d76;font-size:11px;">(' + r.rfc + ')</span>' : '';
146+
return '<div id="test-' + tid + '" style="display:flex;gap:8px;align-items:baseline;padding:6px 0;border-bottom:1px solid #f0f0f0;">'
147+
+ '<div style="min-width:260px;"><code style="font-size:12px;">' + tid + '</code>' + rfc + '</div>'
148+
+ '<div style="min-width:60px;text-align:center;">' + ProbeRender.pill(ProbeRender.EXPECT_BG, r.expected) + '</div>'
149+
+ '<div style="flex:1;font-size:13px;">' + r.reason + '</div>'
150+
+ '</div>';
151+
}
152+
153+
scored.forEach(function (tid) { html += row(tid); });
154+
if (unscored.length > 0) {
155+
html += '<div style="padding:8px 0;font-weight:700;font-size:12px;color:#656d76;border-bottom:1px solid #d0d7de;margin-top:4px;">Not scored (RFC-compliant behavior)</div>';
156+
unscored.forEach(function (tid) { html += row(tid); });
157+
}
158+
html += '</div>';
159+
});
160+
161+
document.getElementById('glossary-tests').innerHTML = html;
162+
})();
163+
</script>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
---
2+
title: Malformed Input
3+
layout: wide
4+
toc: false
5+
---
6+
7+
## Malformed Input Handling
8+
9+
These tests send pathological, oversized, or completely invalid payloads to verify the server handles them gracefully &mdash; rejecting with an appropriate error status rather than crashing, hanging, or consuming unbounded resources.
10+
11+
A well-implemented server should respond with `400 Bad Request`, `414 URI Too Long`, or `431 Request Header Fields Too Large` depending on the violation, or simply close the connection.
12+
13+
**What's tested:**
14+
- **Binary garbage** &mdash; random bytes that aren't valid HTTP at all
15+
- **Oversized fields** &mdash; 100 KB URLs, header names, header values, and method names
16+
- **Too many headers** &mdash; 10,000 headers in a single request
17+
- **Invalid bytes** &mdash; NUL bytes in URL, control characters in header values, non-ASCII in header names and URLs
18+
- **Integer overflow** &mdash; `Content-Length` value exceeding 64-bit integer range
19+
- **Incomplete/empty requests** &mdash; partial HTTP or zero bytes sent
20+
- **Whitespace-only request** &mdash; just spaces/tabs with no method or URI
21+
22+
<div id="table-malformed"><p><em>Loading...</em></p></div>
23+
24+
<script src="/Http11Probe/probe/data.js"></script>
25+
<script src="/Http11Probe/probe/render.js"></script>
26+
<script>
27+
(function () {
28+
if (!window.PROBE_DATA) {
29+
document.getElementById('table-malformed').innerHTML = '<p><em>No probe data available yet. Run the Probe workflow manually on <code>main</code> to generate results.</em></p>';
30+
return;
31+
}
32+
var ctx = ProbeRender.buildLookups(window.PROBE_DATA.servers);
33+
ProbeRender.renderTable('table-malformed', 'MalformedInput', ctx);
34+
})();
35+
</script>

0 commit comments

Comments
 (0)