Overview
Two HTTP request smuggling vulnerabilities in tinyproxy (commit 09312a1). Both allow an attacker to inject requests to the backend server.
Finding 1: CL/TE Desync (CWE-444, CVSS 7.5)
When a client sends both Content-Length and Transfer-Encoding: chunked headers, tinyproxy uses Content-Length to determine body size but forwards BOTH headers to the backend. Per RFC 7230 Section 3.3.3, the backend MUST use Transfer-Encoding when both are present, creating a CL/TE desync.
Vulnerable code
src/reqs.c:917-920:
connptr->content_length.client = get_content_length (hashofheaders);
if (connptr->content_length.client == -1 && is_chunked_transfer (hashofheaders))
connptr->content_length.client = -2;
The chunked check is SKIPPED when Content-Length is present (content_length.client != -1). Both headers are forwarded to the backend (neither is in the skipheaders list at line 887-894).
Attack
- Client sends:
Content-Length: 5\r\nTransfer-Encoding: chunked\r\n
- tinyproxy reads 5 bytes of body (uses CL)
- Backend reads body as chunked (uses TE)
- Data after the chunked terminator is treated as a new request
Finding 2: Duplicate Content-Length (CWE-444, CVSS 7.5)
When a client sends multiple Content-Length headers with different values, tinyproxy uses the FIRST value but forwards ALL duplicate headers. Backend servers using the LAST value read a different body size.
Vulnerable code
src/pseudomap.c:44-56 -- pseudomap_append() adds entries unconditionally (no duplicate detection):
int pseudomap_append(pseudomap *o, const char *key, char *value) {
...
sblist_add(o, &e);
}
src/pseudomap.c:58-66 -- pseudomap_find_index() returns the FIRST match for body read.
The forwarding loop at src/reqs.c:953-971 sends ALL duplicates to the backend.
Attack
- Client sends:
Content-Length: 5\r\nContent-Length: 100\r\n
- tinyproxy uses first CL (5), reads 5 bytes
- Backend uses last CL (100), reads 100 bytes as body
- The extra 95 bytes contain an injected HTTP request
Impact
Both enable classic HTTP request smuggling: cache poisoning, access control bypass, request hijacking against other proxy users.
Fix
- CL/TE: When both headers are present, either reject the request (400) or strip Content-Length before forwarding (per RFC 7230 Section 3.3.3).
- Duplicate CL: Reject requests with multiple Content-Length headers having different values (per RFC 7230 Section 3.3.3).
Overview
Two HTTP request smuggling vulnerabilities in tinyproxy (commit 09312a1). Both allow an attacker to inject requests to the backend server.
Finding 1: CL/TE Desync (CWE-444, CVSS 7.5)
When a client sends both
Content-LengthandTransfer-Encoding: chunkedheaders, tinyproxy uses Content-Length to determine body size but forwards BOTH headers to the backend. Per RFC 7230 Section 3.3.3, the backend MUST use Transfer-Encoding when both are present, creating a CL/TE desync.Vulnerable code
src/reqs.c:917-920:The chunked check is SKIPPED when Content-Length is present (
content_length.client != -1). Both headers are forwarded to the backend (neither is in theskipheaderslist at line 887-894).Attack
Content-Length: 5\r\nTransfer-Encoding: chunked\r\nFinding 2: Duplicate Content-Length (CWE-444, CVSS 7.5)
When a client sends multiple
Content-Lengthheaders with different values, tinyproxy uses the FIRST value but forwards ALL duplicate headers. Backend servers using the LAST value read a different body size.Vulnerable code
src/pseudomap.c:44-56--pseudomap_append()adds entries unconditionally (no duplicate detection):src/pseudomap.c:58-66--pseudomap_find_index()returns the FIRST match for body read.The forwarding loop at
src/reqs.c:953-971sends ALL duplicates to the backend.Attack
Content-Length: 5\r\nContent-Length: 100\r\nImpact
Both enable classic HTTP request smuggling: cache poisoning, access control bypass, request hijacking against other proxy users.
Fix