Jul 10, 2026·6 min read·21 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.
An unauthenticated remote denial of service vulnerability exists in the Unleash feature management platform. By submitting a crafted JSON payload containing deeply nested structures to an OpenAPI-validated endpoint, an attacker can trigger uncontrolled recursion within the error formatting module. This leads to a call-stack exhaustion (RangeError: Maximum call stack size exceeded) inside the Node.js runtime, causing the service to crash immediately without recovery.
CVE-2026-63004 is a server-side request forgery (SSRF) vulnerability in the Unleash feature management platform. Authenticated administrators with CREATE_ADDON or UPDATE_ADDON privileges can exploit this vulnerability to initiate requests to loopback addresses, private networks, and cloud metadata endpoints, potentially leading to information disclosure and credential extraction.
Prior to version 8.0.3, Unleash's Markdown event formatter directly mutated the global template-escaping function of the shared mustache Node.js module, resulting in a process-wide security degradation where HTML/Markdown escaping was permanently disabled for the application lifetime.
A critical SQL injection vulnerability exists in the GeoTools open-source Java library. This vulnerability is situated within the post-processing phase of OGC Filter conversion inside the PostGIS DataStore module. Specifically, the `jsonArrayContains` function does not validate or sanitize its arguments before constructing PostgreSQL SQL/JSON path evaluation queries. An unauthenticated remote attacker can exploit this weakness by submitting crafted filters via standard OGC services like WFS or WMS to execute arbitrary SQL commands on the underlying database system.
CVE-2026-61824 is a high-severity Cross-Site Scripting (XSS) vulnerability in kepano/defuddle before version 0.19.1. Custom site extractors for platforms such as X/Twitter, Substack, and YouTube constructed HTML representations via template string interpolation without output escaping. This allowed malicious pages to bypass standard parser sanitization routines and execute arbitrary JavaScript.
A high-severity vulnerability exists in KeystoneJS, a popular Node.js CMS and GraphQL framework, where the query resolution engine fails to validate signed negative integers within the pagination subsystem. Unauthenticated remote attackers can leverage this flaw to bypass the 'graphql.maxTake' safety boundary. By sending large negative values in the 'take' query parameter, the underlying Prisma ORM interprets the value as an instruction to fetch rows from the end of the collection, allowing malicious actors to bypass pagination limits, trigger database resource exhaustion, and execute application-level Denial of Service (DoS) attacks.