Jul 10, 2026·6 min read·5 visits
Elixir Mint's parser accepted sign-prefixed Content-Length values (like '+100') due to using Integer.parse/1. Intermediaries strictly enforcing RFC 7230/9110 reject or reframe these headers, enabling HTTP response smuggling and connection poisoning.
An Inconsistent Interpretation of HTTP Requests (HTTP Request/Response Smuggling) vulnerability in the Elixir Mint HTTP client allows attacker-controlled HTTP/1 servers to desynchronize response framing on shared connections due to over-lenient parsing of sign-prefixed Content-Length headers.
The Elixir Mint client (elixir-mint/mint) is a low-level, process-less HTTP client designed for high-performance network communication in Erlang and Elixir environments. It is frequently employed in applications that require robust connection pooling, proxy support, and pipeline performance.
In HTTP/1.1 communication, parsing boundaries are defined strictly by the Content-Length or Transfer-Encoding headers. If an HTTP client and an intermediary reverse proxy disagree on the length of a response, they will mismatch where one HTTP response ends and the subsequent response begins on a shared, persistent socket.
This vulnerability arises because Mint's HTTP/1 parser accepts sign-prefixed values (such as +100 or +0) in the Content-Length header. Because strict reverse proxies and load balancers drop or reject such headers, this parser differential creates an exploitation pathway for HTTP request and response smuggling.
The root cause of this vulnerability lies in the use of Elixir's native Integer.parse/1 function within the Mint.HTTP1.Parse.content_length_header/1 function.
Elixir's Integer.parse/1 utility is designed for general-purpose string-to-integer conversion. It parses a leading sign prefix, meaning strings like +123 are successfully parsed as the integer 123, and -10 is parsed as -10. Mint attempted to validate this value by checking if the resulting parsed integer was non-negative (length >= 0), which successfully blocked negative lengths but allowed positive-sign prefixes to pass.
Under RFC 7230 (Section 3.3.2) and RFC 9110 (Section 8.6), the standard HTTP/1.1 specification defines the grammar of Content-Length using the following ABNF rule:
Content-Length = 1*DIGITThis specification strictly restricts the characters in the header to ASCII digits (0-9). It explicitly forbids any sign prefix, including + or -. When an upstream server under an attacker's control responds to Mint with Content-Length: +100, Mint processes this as a valid message body of 100 bytes. However, an intermediary proxy implementing strict RFC validation will flag +100 as invalid, and may treat the response body as having a length of zero or ignore the message framing altogether. This difference in implementation creates a classic response-smuggling condition.
The vulnerable logic has existed in Mint's ancestral codebase since 2017. It was originally introduced in the legacy xhttp client library in commit 65e0e86d799a6d3b08e4372fccdd9747535e0dd6 before being migrated into Mint's lib/mint/http1/parse.ex file.
Below is the vulnerable implementation in Mint before the fix:
def content_length_header(string) do
# String.trim_trailing/1 is executed, then Integer.parse/1 converts the string
case Integer.parse(String.trim_trailing(string)) do
{length, ""} when length >= 0 -> {:ok, length}
_other -> {:error, {:invalid_content_length_header, string}}
end
endTo remediate this parsing flaw, the maintainers modified the header processor in commit 47e48027480228e4e32a0b4df39db497b4804921 to validate the string before parsing it. The revised implementation uses a custom pattern-matching function only_digits?/1 to ensure that only standard ASCII digits are passed to String.to_integer/1:
def content_length_header(string) do
trimmed = String.trim_trailing(string)
# Strictly enforce that the trimmed string contains only ASCII digits
if only_digits?(trimmed) do
{:ok, String.to_integer(trimmed)}
else
{:error, {:invalid_content_length_header, string}}
end
end
# Helper function to recursively check for strict ASCII digits (0x30 to 0x39)
defp only_digits?(<<char>>) when is_digit(char), do: true
defp only_digits?(<<char, rest::binary>>) when is_digit(char), do: only_digits?(rest)
defp only_digits?(_other), do: falseThis change successfully eliminates the use of Integer.parse/1 for input validation and blocks sign prefixes, hexadecimal indicators, and spaces.
Exploitation relies on a shared connection architecture where the Mint HTTP client connects to an untrusted upstream server through an intermediary proxy. A typical scenario involves an application hosting a webhook service, an SSRF-vulnerable interface, or a reverse proxy utilizing the Mint client.
An attacker controls the destination server and triggers an outbound request from the Mint client. The attacker's server then responds with a payload designed to split the connection buffer:
HTTP/1.1 200 OK
Content-Length: +50
Connection: keep-alive
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 19
<script>alert(1)</script>The proxy, receiving this sequence, rejects +50 as an invalid Content-Length. It processes the header as 0 or treats the response as terminated. It then considers the trailing bytes containing the second HTTP header as the start of a pipelined HTTP response or leaves them in the pipeline. Mint, on the other hand, reads exactly 50 bytes of response body and completes its cycle.
When a victim subsequently requests a resource over the same pooled connection, the proxy matches the victim's request with the remaining smuggled bytes left in the socket stream. The victim is then served the smuggled response containing the attacker's script payload, resulting in cross-site scripting (XSS), credential leakage, or session hijacking.
A detailed security analysis of the patch reveals a subtle edge-case behavior that could potentially be targeted in specialized environments. The patch executes trimmed = String.trim_trailing(string) prior to performing the only_digits?/1 check.
In Elixir, String.trim_trailing/1 is Unicode-aware. It strips not only standard ASCII carriage returns, line feeds, and horizontal tabs, but also any Unicode-defined trailing whitespace character. This includes characters such as the No-Break Space (\u00A0), Ogham Space Mark (\u1680), or En Quad (\u2000).
If an attacker provides a header containing a trailing Unicode space character:
Content-Length: 100\u00A0Mint's Unicode-aware trimmer strips the trailing \u00A0, leaving the string "100". This passes the only_digits?/1 check, and Mint processes it as a valid content length of 100 bytes. However, many strict intermediary proxies and load balancers do not recognize Unicode spaces as valid Optional Whitespace (OWS) under RFC rules. Standard proxies recognize only ASCII Space (0x20) and Horizontal Tab (0x09).
Such a proxy will view the non-ASCII character as an invalid character, causing it to ignore the header or close the connection. This discrepancy maintains a minor parser differential that could allow for response smuggling in environments where the intermediary enforces strict ASCII-only OWS validation while Mint performs Unicode-aware trimming. To completely close this attack vector, the parser should be hardened to strip only strict ASCII whitespace characters.
The primary remediation for this vulnerability is to upgrade the mint dependency to version 1.9.0 or higher. Developers should update their mix.exs configuration file and run mix deps.get to fetch the patched library.
For environments where immediate upgrades are not possible, several defense-in-depth measures can mitigate the risk. Network administrators should configure Web Application Firewalls (WAF) or Reverse Proxies to drop incoming responses from upstream servers that contain non-numeric characters inside the Content-Length header.
Disabling connection reuse (such as turning off Keep-Alive) or isolating connection pools by user session prevents the multiplexing of untrusted upstream connections with legitimate client sessions, removing the primary vector required to execute smuggling attacks.
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:L/VA:N/SC:L/SI:L/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
mint elixir-mint | >= 0.1.0, < 1.9.0 | 1.9.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-444 |
| Attack Vector | Network |
| CVSS v4.0 | 6.3 |
| EPSS Score | 0.00301 |
| Impact | HTTP Request/Response Smuggling |
| Exploit Status | None |
| KEV Status | Not Listed |
The program does not properly parse or interpret HTTP requests, which can lead to HTTP request or response smuggling.
CVE-2026-48861 is a client-side HTTP request-line CRLF (Carriage Return Line Feed) injection vulnerability in the popular Elixir HTTP client library, Mint. The vulnerability permits HTTP Request Splitting and HTTP Request Smuggling when an application forwards untrusted, attacker-controlled inputs to Mint's HTTP client requests as either the HTTP request method or target. By embedding CRLF characters within these parameters, an attacker can terminate the request line prematurely, inject malicious headers, or pipeline entirely independent requests. These smuggled requests are then processed by upstream or downstream proxy servers as separate HTTP queries on the same TCP connection. While Mint version 1.7.0 introduced target validation to secure the request target, the HTTP request method parameter remained completely unvalidated. This flaw allows attackers to bypass routing filters, access restricted internal APIs, or poison HTTP caches under default configurations.
An allocation of resources without limits or throttling vulnerability in Elixir Mint allows an attacker-controlled HTTP/2 server to exhaust memory in a Mint client. The vulnerability is exploited by sending a HEADERS frame without the END_HEADERS flag followed by an infinite stream of CONTINUATION frames. Because the client lacks limits on the incoming header-block accumulator, the client continuously consumes memory until an out-of-memory crash occurs.
CVE-2026-48596 is an Improper Neutralization of CRLF Sequences in HTTP Headers (HTTP Request/Response Splitting, CWE-113) in the Elixir Tesla HTTP client. The flaw resides in how multipart content-type parameters are joined and serialized, enabling attackers to inject arbitrary headers or split HTTP requests when applications pass untrusted inputs to the parameters of multipart uploads.
An improper handling of highly compressed data (decompression bomb) vulnerability exists in the Elixir Tesla HTTP client when utilizing response decompression middlewares. By serving highly compressed responses or stacked content-encoding headers, a malicious server can cause arbitrary heap exhaustion, leading to a denial of service (DoS) crash in the BEAM virtual machine.
A high-severity security vulnerability in Elixir's Tesla HTTP client library (CVE-2026-48595) allows unauthenticated remote attackers to harvest sensitive credentials, including Authorization headers and cookies. The flaw resides in the 'Tesla.Middleware.FollowRedirects' component, which performs case-sensitive lookups when stripping credentials during cross-origin redirects. Because HTTP headers are case-insensitive by RFC specifications, standard canonical casing (e.g., 'Authorization') bypasses the lowercase-only blocklist, leaking tokens to untrusted external redirect destinations.
CVE-2026-48597 is a high-severity Denial of Service (DoS) vulnerability in the Elixir HTTP client library Tesla (specifically involving the Mint adapter) that allows an unauthenticated remote attacker to cause an unrecoverable crash of the Erlang Virtual Machine (BEAM). The flaw arises from the dynamic conversion of untrusted URL schemes into Erlang atoms without validation, leading to global atom table exhaustion.