CVE-2026-73812 Overview
CVE-2026-73812 is an HTTP Request Smuggling vulnerability in the Erlang/OTP inetshttpd HTTP server. The check_header/3 function rejects duplicate Content-Length headers but never validates the co-presence of Transfer-Encoding and Content-Length, which RFC 9112 §6.3 identifies as a probable smuggling attempt. The handle_body/3 function frames requests using chunked encoding and silently discards Content-Length. When paired with a Content-Length-preferring front-end, this creates a classic CL.TE front-end/back-end desynchronization [CWE-444].
Critical Impact
Attackers can smuggle HTTP requests past front-end proxies to poison connections, bypass access controls, or hijack sessions handled by the Erlang inets back-end.
Affected Products
- Erlang/OTP 17.0 through versions before OTP 27.3.4.17 (inets 5.10 before 9.3.2.7)
- Erlang/OTP 28.0 through versions before OTP 28.5.0.6 (inets 9.4 before 9.6.2.3)
- Erlang/OTP 29.0 through versions before OTP 29.0.6 (inets 9.7 before 9.7.2)
Discovery Timeline
- 2026-09-01 - CVE-2026-73812 published to NVD
- 2026-09-01 - Last updated in NVD database
Technical Details for CVE-2026-73812
Vulnerability Analysis
The Erlang inetshttpd server exposes an HTTP Request Smuggling condition when processing requests that contain both Transfer-Encoding: chunked and Content-Length headers. RFC 9112 §6.3 requires servers to reject such requests as ambiguous. The httpd implementation only defends against duplicate Content-Length values, a fix originally introduced for CVE-2026-23941.
Once a request is accepted, handle_body/3 selects chunked framing and discards the Content-Length value without warning. Any upstream proxy that prefers Content-Length will disagree with inets about where one request ends and the next begins. This mismatch allows an attacker to prepend attacker-controlled bytes to a victim's next request on a shared keep-alive connection.
Root Cause
The check_header/3 function in lib/inets/src/http_server/httpd_request.erl inspects headers individually without cross-referencing other parsed headers. Because framing headers were never compared against each other, the mutually exclusive Transfer-Encoding + Content-Length combination flowed through validation unmodified.
Attack Vector
Exploitation requires an HTTP topology where a Content-Length-preferring reverse proxy or CDN forwards traffic to an inets back-end. The attacker sends a single crafted request containing both framing headers. The front-end forwards the full body based on Content-Length; the back-end consumes only the chunked portion and treats the remainder as the start of a subsequent request.
The upstream security patch introduces a rejection path and error constant. From lib/inets/src/http_server/httpd_internal.hrl:
{timefmt,"%A, %d-%b-%y %T %Z"},
{sizefmt,"abbrev"}]).
-define(CL_TE_ERROR, "Transfer-Encoding and Content-Length headers in the same request are forbidden").
-endif. % -ifdef(httpd_internal_hrl).
Source: GitHub OTP Commit 591dc00
The validation callsite in lib/inets/src/http_server/httpd_request.erl now passes the full header list so cross-header checks can execute:
{ok, list_to_tuple(lists:reverse([Body, {http_request:headers(FinalHeaders, #http_request_h{}), FinalHeaders} | Result]))};
NewHeader ->
case check_header(NewHeader, Headers, Options) of
ok ->
FinalHeaders = lists:filtermap(fun(H) ->
httpd_custom:customize_headers(Customize, request_header, H)
Source: GitHub OTP Commit 591dc00
Detection Methods for CVE-2026-73812
Indicators of Compromise
- Inbound HTTP requests to Erlang inets back-ends that carry both Transfer-Encoding and Content-Length headers.
- Proxy or web server access logs showing truncated request bodies immediately followed by malformed request lines on the same TCP connection.
- Unexpected 400 Bad Request responses interleaved with successful requests from the same client source.
Detection Strategies
- Inspect request streams at the proxy layer for the concurrent presence of Transfer-Encoding: chunked and Content-Length, and drop such requests.
- Correlate front-end and back-end request identifiers to identify per-connection request count mismatches that suggest desynchronization.
- Alert on abnormal HTTP methods, hosts, or paths appearing without matching front-end log entries.
Monitoring Recommendations
- Ship both proxy and inets HTTP access logs to a centralized analytics platform for correlation across the request path.
- Monitor for spikes in chunked-encoded requests originating from untrusted client networks.
- Track deployed Erlang/OTP and inets versions across your fleet and flag hosts running versions listed in the advisory.
How to Mitigate CVE-2026-73812
Immediate Actions Required
- Upgrade Erlang/OTP to 27.3.4.17, 28.5.0.6, or 29.0.6 depending on your branch, ensuring inets reaches 9.3.2.7, 9.6.2.3, or 9.7.2 respectively.
- Inventory all internal services exposing httpd from inets, including administrative and telemetry endpoints commonly deployed behind reverse proxies.
- Configure upstream proxies and load balancers to reject requests that contain both Transfer-Encoding and Content-Length headers.
Patch Information
The fix is committed in Erlang/OTP commit 591dc00dc99dc2a426167a3b5257c0c94bd45e91. The patch updates check_header/3 to receive the full header list and rejects any request that presents both framing headers with the error string defined by ?CL_TE_ERROR. See the GitHub Security Advisory GHSA-7j6m and the CNA CVE-2026-73812 Summary for release notes.
Workarounds
- Terminate HTTP at a hardened proxy such as nginx or HAProxy configured to normalize or reject ambiguous framing before traffic reaches inets.
- Disable HTTP keep-alive on connections between the proxy and the inets back-end to limit smuggled request persistence.
- Restrict inetshttpd exposure to internal networks and enforce mutual TLS on any external listener until patching completes.
# nginx snippet: reject requests carrying both framing headers
map "$http_transfer_encoding:$http_content_length" $smuggle_attempt {
default 0;
"~.+:.+" 1;
}
server {
if ($smuggle_attempt) { return 400; }
location / { proxy_pass http://inets_backend; }
}
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.