Skip to main content
Vulnerability Database/CVE-2026-73812

CVE-2026-73812: Erlang OTP HTTP Request Smuggling Vulnerability

CVE-2026-73812 is an HTTP request smuggling flaw in Erlang OTP inets httpd that fails to detect Transfer-Encoding and Content-Length co-presence, enabling classic CL.TE desync attacks. This post covers technical details, affected OTP versions, impact, and mitigation strategies.

Published:

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:

erlang
 {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:

erlang
            {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.
bash
# 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.

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.