Jul 10, 2026·6 min read·12 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.
Grav CMS prior to version 1.7.53 and 2.0.0-rc.8 is vulnerable to an unauthenticated remote denial of service (DoS) vulnerability. By supplying crafted query parameters with extremely large dimensions to image assets, remote unauthenticated attackers can force the server to allocate massive amounts of system memory, leading to kernel Out-Of-Memory (OOM) termination of web worker processes.
CVE-2026-53657 is a local privilege escalation vulnerability in Lima (lima-vm/lima) affecting versions prior to 2.1.3 when configured with the QEMU driver. The guest agent daemon, running as root, creates its communication socket `/run/lima-guestagent.sock` with world-writable permissions (0777). This allows unprivileged local users to command the agent to establish arbitrary tunnels, including to privileged local UNIX sockets (like D-Bus). Because the target daemon authenticates the incoming connection using the credentials of the root-owned guest agent (via SO_PEERCRED), unprivileged users can perform root operations, resulting in complete guest VM compromise.
An unauthenticated Denial of Service vulnerability exists in the s2n-quic library's CryptoStream reassembler due to a lack of buffer limits on out-of-order cryptographic frames. An attacker can transmit a crafted CRYPTO frame with an extremely high offset and nominal payload, forcing the receiver to execute unbounded memory allocations and causing service crashes.
A JNDI Injection and Deserialization Gadget vulnerability exists in mchange-commons-java prior to version 0.6.0. The com.mchange.v2.naming.JavaBeanObjectFactory component permits arbitrary class instantiation and setter invocation, allowing attackers to perform Server-Side Request Forgery (SSRF) and remote class loading.
SurrealDB versions supporting element-level SELECT permissions on arrays are vulnerable to a logical authorization bypass. Due to an index-shifting error during array filtration, restricted elements can skip permission checks and leak to unauthorized record users.
CVE-2026-12243 is a path traversal vulnerability in the Natural Language Toolkit (NLTK) version 3.9.4. The flaw exists because the input validation routine fails to account for percent-encoded directory traversal sequences like '..%2f' before passing them to urllib.request.url2pathname(), which decodes them into active traversal sequences.