In early 2025, security researchers discovered a troubling issue in the widely used h11 Python library—a pure-Python implementation of HTTP/1.1. This issue, now tracked as CVE-2025-43859, is a reminder that the smallest parsing quirks can lead to serious web application vulnerabilities, like HTTP request smuggling.
Here, we'll break down what the bug is, show you what the code looks like, demonstrate how it can be abused, and, most importantly, show you how to fix it. We're writing this in simple American English and trying to make the summary as clear as possible.
What is CVE-2025-43859?
The h11 library (versions before .16.) is a fundamental building block for many Python web servers and frameworks. It lets Python applications understand and compose HTTP/1.1 messages.
A parsing bug existed in how h11 handled chunked transfer encoding—specifically, in its leniency towards line terminators at the ends of chunked message parts. While that might sound nitpicky, this is exactly the kind of "edge case" where security issues hide.
If you combine a buggy h11 server with a buggy reverse proxy, attackers could sneak past normal HTTP security controls by crafting HTTP requests that the front and back ends interpret differently. This is the textbook definition of HTTP request smuggling.
Vulnerable library: h11 < .16.
- Patched in: h11==.16.
- CVE ID: CVE-2025-43859
Reference:
- h11 GitHub Security Advisory
What Is HTTP Request Smuggling?
HTTP request smuggling is when an attacker crafts a single HTTP message that different components of a web stack interpret in different, conflicting ways. Usually, they target disagreements in parsing between a front-end (load balancer, cache or reverse proxy) and a back-end server.
and more
It's one of those vulnerabilities that are super hard to spot—but can result in complete bypass of security mechanisms!
Where Was The Bug In h11?
The core problem lies in how h11 parses chunked transfer-encoded bodies. According to the HTTP/1.1 standard (RFC 723, section 3.3.1), each chunk ends with \r\n.
However, h11 before .16. was too lenient:
It mis-accepted chunked lines ending with just \n, instead of strict \r\n.
Normally, that's not immediately catastrophic. But if your reverse proxy *does* expect strict \r\n, it will interpret the boundaries between HTTP requests differently from the back end. That's where the trouble—and the smuggling—starts.
Example: Malicious Chunked Request
Suppose the reverse proxy expects chunked segments to end with \r\n, but h11 (the back-end) also accepts just \n. An attacker could sneak a second HTTP request in the same connection, which the back-end would process as a whole new request—but the proxy would never see it!
Here's a basic Python snippet that triggers the buggy behavior on vulnerable h11 versions
import h11
conn = h11.Connection(h11.SERVER)
# This is a malicious chunked HTTP request:
# Note that the chunk size line ends with just '\n', not '\r\n'
malicious_request = (
b"POST / HTTP/1.1\r\n"
b"Host: vulnerable.local\r\n"
b"Transfer-Encoding: chunked\r\n"
b"\r\n"
b"5\n"
b"hello"
b"\n\n"
b"\r\n"
b"GET /admin HTTP/1.1\r\n"
b"Host: vulnerable.local\r\n"
b"\r\n"
)
conn.receive_data(malicious_request)
while True:
event = conn.next_event()
if isinstance(event, h11.Request):
print("Received a request:", event)
elif isinstance(event, h11.EndOfMessage):
print("End of message.")
break
On an h11 version before .16., this request would successfully parse and *process the second, smuggled GET request*!
How Does Exploitation Happen?
Exploiting this bug is tricky—it only works if both the reverse proxy and the back-end application are buggy in just the right ways.
The attacker crafts a request with chunked bodies terminated by \n lines.
2. The reverse proxy up front (which is stricter) fails to see the extra data as a second request—so it thinks everything’s fine.
3. The h11 back end parses the data loosely, sees the smuggled request, and processes it as a new, valid request.
The attacker can now send arbitrary requests *past* proxy-level controls!
In real life, this usually requires you to create a *lab* with both a buggy reverse proxy and a buggy h11 back end. Exploitation in production is possible, but not guaranteed everywhere.
You use a strict, up-to-date reverse proxy that rejects malformed chunked requests
In other words, fixing either side is enough. If you're responsible for a Python app that talks HTTP via h11, upgrade to .16. or higher immediately!
How To Patch
pip install --upgrade h11
Or, in your requirements.txt
h11>=.16.
Restart your deployment to ensure the patch is effective!
TL;DR
- CVE-2025-43859 affects h11 before .16., letting attackers "smuggle" HTTP requests with malformed chunked message bodies.
Upgrade h11 to .16.+ or ensure your proxies are not similarly lenient.
- See h11’s GitHub Security Advisory for original notice.
Further Reading & References
- h11 GitHub: .16. Release Notes
- h11 Security Advisory
- Understanding Request Smuggling (PortSwigger)
- RFC 723: HTTP/1.1 Message Syntax and Routing
Stay patched and stay safe—HTTP parsing may seem boring, but it's where serious vulnerabilities often hide!
Timeline
Published on: 04/24/2025 19:15:47 UTC