CVE-2026-54387 Overview
CVE-2026-54387 is an HTTP request smuggling vulnerability in Tinyproxy through version 1.11.3. The proxy fails to reconcile conflicting Content-Length and Transfer-Encoding: chunked headers in client requests. Tinyproxy forwards both headers verbatim to the backend while using Content-Length to determine how many request body bytes to consume. Remote, unauthenticated attackers can desynchronize the proxy and backend parser state, enabling injection of arbitrary HTTP requests to the backend. The flaw is tracked as [CWE-444] HTTP Request/Response Smuggling and was fixed in commit ff45d3b.
Critical Impact
Attackers can poison caches, bypass access controls, and hijack requests from other users by smuggling crafted HTTP requests through the proxy.
Affected Products
- Tinyproxy versions up to and including 1.11.3
- Deployments using Tinyproxy as a forward or reverse HTTP proxy
- Backend services reachable through vulnerable Tinyproxy instances
Discovery Timeline
- 2026-06-17 - CVE-2026-54387 published to NVD
- 2026-06-17 - Last updated in NVD database
- Fix commit - Tinyproxy commit ff45d3b resolves the desynchronization
Technical Details for CVE-2026-54387
Vulnerability Analysis
The vulnerability is a classic CL.TE (Content-Length / Transfer-Encoding) request smuggling weakness. HTTP/1.1 specifies that when both Content-Length and Transfer-Encoding: chunked headers appear in the same request, the Transfer-Encoding value must take precedence and the Content-Length value must be ignored or removed. Tinyproxy violated this requirement in src/reqs.c by forwarding both headers unchanged to the backend while internally using Content-Length to delimit the request body. When the upstream backend parses the same request using Transfer-Encoding: chunked, the two endpoints disagree on where one request ends and the next begins. An attacker controlling the body content can place additional HTTP request bytes inside what Tinyproxy treats as the body, which the backend then interprets as a new, separate request.
Root Cause
The defect lies in the header reconciliation logic in src/reqs.c. The original code only treated a request as chunked when Content-Length was absent, leaving conflicting requests to flow through with both framing mechanisms intact. There was no normalization step to remove the redundant Content-Length header before forwarding.
Attack Vector
An unauthenticated remote attacker sends a single crafted HTTP request containing both Content-Length and Transfer-Encoding: chunked headers. The smuggled portion of the body is parsed by the backend as the start of the next victim request, enabling cache poisoning, access control bypass, response queue poisoning, and hijacking of requests issued by other clients sharing the connection.
connptr->content_length.client = get_content_length (hashofheaders);
/* Check whether client sends chunked data. */
- if (connptr->content_length.client == -1 && is_chunked_transfer (hashofheaders))
+ if (is_chunked_transfer (hashofheaders)) {
+ if (connptr->content_length.client != -1)
+ /* request smuggling, see GH issue #609 */
+ pseudomap_remove (hashofheaders, "content-length");
+
connptr->content_length.client = -2;
+ }
/*
* See if there is a "Connection" header. If so, we need to do a bit
Source: Tinyproxy commit ff45d3b. The patch strips the conflicting Content-Length header when chunked transfer encoding is also present, forcing a single, unambiguous framing mechanism before the request is forwarded.
Detection Methods for CVE-2026-54387
Indicators of Compromise
- Inbound HTTP requests that contain both Content-Length and Transfer-Encoding: chunked headers in the same message.
- Backend access logs showing requests with methods, paths, or hosts that Tinyproxy did not log on the front end.
- Unexpected HTTP/1.1 request lines appearing inside POST or PUT request bodies captured at the proxy.
- Cache entries serving content for paths that were not requested by legitimate clients.
Detection Strategies
- Inspect HTTP traffic at the proxy boundary and alert on any request carrying both framing headers, since well-behaved clients should never send both.
- Correlate front-end proxy logs with backend application logs to identify request count or path mismatches indicative of smuggling.
- Deploy network signatures that flag Transfer-Encoding: chunked combined with a non-zero Content-Length over the same connection.
Monitoring Recommendations
- Enable verbose request logging on Tinyproxy and forward logs to a centralized analytics platform for correlation with backend logs.
- Monitor backend services for HTTP 400 spikes or anomalous methods, which often follow desynchronization attempts.
- Track the Tinyproxy binary version and build commit across the fleet to detect unpatched instances.
How to Mitigate CVE-2026-54387
Immediate Actions Required
- Upgrade Tinyproxy to a build that includes commit ff45d3b or later.
- Inventory all Tinyproxy deployments, including container images and embedded appliances, and identify versions at or below 1.11.3.
- Place a hardened reverse proxy or web application firewall in front of Tinyproxy until patching is complete.
- Restrict network exposure of Tinyproxy listeners to trusted client ranges only.
Patch Information
The upstream fix is available in Tinyproxy commit ff45d3bf0e61d0f8ed97ab379d3047f04eb67521. Additional context is published in GitHub Issue #609, Pull Request #610, and the VulnCheck advisory. Rebuild Tinyproxy from source at or beyond the fix commit, or install a distribution package that backports the change.
Workarounds
- Configure an upstream layer-7 device to reject any request that contains both Content-Length and Transfer-Encoding headers.
- Disable HTTP keep-alive on the backend so a desynchronized connection cannot carry smuggled requests across transactions.
- Force HTTP/2 between the proxy and backend where supported, since HTTP/2 framing is not vulnerable to CL.TE confusion.
# Example WAF / front-end rule to drop conflicting framing headers
# nginx fragment placed in front of Tinyproxy
if ($http_transfer_encoding ~* chunked) {
set $te_present 1;
}
if ($http_content_length != "") {
set $cl_present 1;
}
if ($te_present$cl_present = 11) {
return 400;
}
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

