Feb 28, 2026·6 min read·45 visits
aiohttp failed to restrict the parsing of the HTTP 'Range' header to ASCII digits. Python's default regex engine interprets non-ASCII Unicode digits (e.g., Devanagari numerals) as valid numbers. This discrepancy allows attackers to bypass proxy filters or desynchronize the interpretation of the request, leading to HTTP Request Smuggling or Cache Poisoning. Fixed in version 3.13.3.
A differential interpretation vulnerability exists in aiohttp versions 3.13.2 and earlier, caused by the mishandling of Unicode digits in the HTTP 'Range' header. This flaw allows attackers to smuggle requests or poison web caches by injecting non-ASCII numeric characters that are interpreted as valid digits by the Python backend but treated as invalid or text by upstream proxies.
CVE-2025-69225 represents a semantic parsing vulnerability within the aiohttp library, a widely used asynchronous HTTP client/server framework for Python. The vulnerability resides in the server-side handling of the HTTP Range header, specifically within the aiohttp.web_request module.
Modern web architectures typically involve a chain of systems processing a single HTTP request—load balancers, WAFs, reverse proxies (like Nginx or HAProxy), and finally the application backend. Security relies on these systems having a consistent interpretation of the HTTP protocol. This vulnerability breaks that consistency. While the HTTP standards (RFC 9110/9112) imply that header values like byte ranges should consist of ASCII digits (0-9), aiohttp leveraged Python's permissive string handling to accept a broader range of Unicode numeric characters.
This behavior introduces a classic 'differential interpretation' attack surface. An attacker can craft an HTTP request containing Unicode digits (e.g., '५' for '5') in the Range header. A strict frontend proxy may view this as an invalid header, a distinct textual string, or garbage data, potentially forwarding it without normalization. The aiohttp backend, however, parses these characters as valid integers. This divergence creates the conditions necessary for HTTP Request Smuggling (HRS) and Cache Poisoning.
The root cause of this vulnerability lies in the default behavior of Python's re (regular expression) module combined with the int() constructor, neither of which defaults to strict ASCII enforcement in Python 3.
In Python 3, the regular expression character class \d (digit) matches any character in the Unicode category Nd (Number, Decimal Digit). This includes standard ASCII digits [0-9], but also hundreds of other characters from various scripts, such as:
५ (U+096B, Value: 5)١ (U+0661, Value: 1)1 (U+FF11, Value: 1)The vulnerable code in aiohttp utilized the regex pattern r"^bytes=(\d*)-(\d*)$" without the re.ASCII flag. Consequently, the pattern matches strings like bytes=0-५. When the captured group ५ is passed to Python's int() function, it is successfully converted to the integer 5.
Upstream infrastructure (written in C, Go, or Rust) typically relies on standard ASCII byte processing. When a proxy sees Range: bytes=0-५, it does not interpret it as a valid byte range request because ५ is not in the ASCII range 0x30-0x39. The proxy might ignore the header or forward it as a generic custom header. aiohttp, acting on the same input, processes it as a valid range request bytes=0-5, altering the response content (e.g., returning a 206 Partial Content status). This specific misalignment allows attackers to manipulate the response state without the proxy being aware.
The vulnerability existed in aiohttp/web_request.py within the http_range property. Below is the analysis of the vulnerable code and the remediation applied in version 3.13.3.
# aiohttp/web_request.py
@property
def http_range(self) -> slice:
rng = self.headers.get(hdrs.RANGE)
if rng is not None:
try:
# VULNERABILITY: \d matches Unicode digits by default in Python 3
pattern = r"^bytes=(\d*)-(\d*)$"
start, end = re.findall(pattern, rng)[0]
# int() also accepts Unicode digits
if start:
start = int(start)
if end:
end = int(end)
# ...The fix, applied in commit c7b7a044f88c71cefda95ec75cdcfaa4792b3b96, forces the regex engine to operate in ASCII-only mode. This ensures that \d only matches characters [0-9].
# aiohttp/web_request.py
@property
def http_range(self) -> slice:
rng = self.headers.get(hdrs.RANGE)
if rng is not None:
try:
pattern = r"^bytes=(\d*)-(\d*)$"
# FIX: re.ASCII flag restricts matching to [0-9]
start, end = re.findall(pattern, rng, re.ASCII)[0]
if start:
start = int(start)
# ...This simple one-line change aligns the application's parsing logic with the strict expectations of the HTTP RFCs and upstream infrastructure, effectively neutralizing the attack vector.
The exploitation of this vulnerability relies on the presence of an intermediary system that inspects or acts upon HTTP headers but interprets them differently than aiohttp.
Range headers to prevent cache fragmentation.main.js) with the header Range: bytes=0-५.Range header invalid, and assumes the backend will return the full file (200 OK). It prepares to cache the response associated with the URL.aiohttp parses ५ as 5, interprets the header as bytes=0-5, and returns a 206 Partial Content response containing only the first 6 bytes of the file.main.js.main.js receive the corrupted 6-byte file, causing a denial of service for that asset.The impact of CVE-2025-69225 is classified as Medium (CVSS 5.3). While the mechanism allows for protocol manipulation, the actual impact is highly dependent on the architecture of the deployed environment.
Prerequisites: The attack requires no authentication (PR:N) and can be executed remotely (AV:N). However, it requires a specific infrastructure setup involving a disparity between the proxy and the backend. Standalone aiohttp instances without an upstream proxy are generally not vulnerable to the smuggling aspect, though they will still process the unexpected range.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
aiohttp aio-libs | <= 3.13.2 | 3.13.3 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-436 |
| Attack Vector | Network |
| CVSS v3.1 | 5.3 (Medium) |
| CVSS v4.0 | 2.7 (Low) |
| Impact | Cache Poisoning / Request Smuggling |
| Exploit Status | PoC Available |
Interpretation Conflict
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 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.
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.