---
id: "CVE-2025-43859"
kind: "vulnerability"
aliases: ["CVE-2025-43859", "GHSA-vqfr-h8mv-ghfj"]
title: "h11 accepts some malformed Chunked-Encoding bodies"
severity: "critical"
cvss: 9.1
epss: 0.00594
exploited: false
status: "open"
category: "package"
products: [{"name": "h11", "fixed": ["0.16.0"], "affected": "< 0.16.0", "ecosystem": "pypi"}]
ecosystems: ["pypi"]
tags: ["cwe-444", "httpcore", "package", "python", "reverse-proxy", "self-hosted", "uvicorn"]
not_affected_if: ["h11-0.16-or-later", "managed-hosting", "no-reverse-proxy"]
published_at: "2025-04-24T16:07:56+00:00"
first_seen_at: "2026-10-27T16:35:55+00:00"
updated_at: "2026-10-27T16:38:08+00:00"
sources: [{"source": "ghsa", "url": "https://github.com/advisories/GHSA-vqfr-h8mv-ghfj", "first_seen_at": "2026-10-27T16:35:55+00:00"}, {"source": "nvd", "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-43859", "first_seen_at": "2026-10-27T17:03:04+00:00"}]
---

# h11 accepts some malformed Chunked-Encoding bodies

The h11 Python HTTP/1.1 library accepts malformed chunked-encoding bodies, skipping validation of the trailing CRLF after each chunk. When paired with a reverse proxy that parses chunked bodies differently, an attacker can smuggle a second request past the proxy and steal another user's session cookie or bypass access controls.

_Summary, check and fix written by a model from the sources; labelled as such._

## Affected

- pypi:h11 affected < 0.16.0 fixed 0.16.0

## How to check

- Run `pip show h11` or `pip freeze | grep -i h11` and check whether the version is below `0.16.0`
- Check whether h11 is used behind a reverse proxy (nginx, HAProxy, Pound, a cloud load balancer) that forwards chunked requests to an h11-based server such as uvicorn or httpcore
- Review the proxy's chunked-encoding parser for the same flaw described in the advisory

## Fix

- Upgrade h11 to `0.16.0` or later (the advisory says fixed in `0.15.0`; the affected range in the source is below `0.16.0`)
- Alternatively, fix or harden the reverse proxy's chunked parsing so it rejects bodies with malformed chunk terminators

## Timeline

- 2026-10-27T16:35:55+00:00 ghsa https://github.com/advisories/GHSA-vqfr-h8mv-ghfj
- 2026-10-27T17:03:04+00:00 nvd https://nvd.nist.gov/vuln/detail/CVE-2025-43859

## From the sources

### Impact

A leniency in h11's parsing of line terminators in chunked-coding message bodies can lead to request smuggling vulnerabilities under certain conditions.

### Details

HTTP/1.1 Chunked-Encoding bodies are formatted as a sequence of "chunks", each of which consists of:

- chunk length
- `\r\n`
- `length` bytes of content
- `\r\n`

In versions of h11 up to 0.14.0, h11 instead parsed them as:

- chunk length
- `\r\n`
- `length` bytes of content
- any two bytes

i.e. it did not validate that the trailing `\r\n` bytes were correct, and if you put 2 bytes of garbage there it would be accepted, instead of correctly rejecting the body as malformed.

By itself this is harmless. However, suppose you have a proxy or reverse-proxy that tries to analyze HTTP requests, and your proxy has a _different_ bug in parsing Chunked-Encoding, acting as if the format is:

- chunk length
- `\r\n`
- `length` bytes of content
- more bytes of content, as many as it takes until you find a `\r\n`

For example, [pound](https://github.com/graygnuorg/pound/pull/43) had this bug -- it can happen if an implementer uses a generic "read until end of line" helper to consumes the trailing `\r\n`.

In this case, h11 and your proxy may both accept the same stream of bytes, but interpret them differently. For example, consider the following HTTP request(s) (assume all line breaks are `\r\n`):

```
GET /one HTTP/1.1
Host: localhost
Transfer-Encoding: chunked

5
AAAAAXX2
45
0

GET /two HTTP/1.1
Host: localhost
Transfer-Encoding: chunked

0
```

Here h11 will interpret it as two requests, one with body `AAAAA45` and one with an empty body, while our hypothetical buggy proxy will interpret it as a single request, with body `AAAAXX20\r\n\r\nGET /two ...`. And any time two HTTP processors both accept the same string of bytes but interpret them differently, you have the conditions for a "request smuggling" attack. For example, if `/two` is a dangerous endpoint and the job of the reverse proxy is to stop requests from getting there, then an attacker could use a bytestream like the above to circumvent this protection.

Even worse, if our buggy reverse proxy receives two requests from different users:

```
GET /one HTTP/1.1
Host: localhost
Transfer-Encoding: chunked

5
AAAAAXX999
0
```

```
GET /two HTTP/1.1
Host: localhost
Cookie: SESSION_KEY=abcdef...
```

...it will consider the first request to be complete and valid, and send both on to the h11-based web server over the same socket. The server will then see the two concatenated requests, and interpret them as _one_ request to `/one` whose body includes `/two`'s session key, potentially allowing one user to steal another's credentials.

### Patches

Fixed in h11 0.15.0.

### Workarounds

Since exploitation requires the combination of buggy h11 with a buggy (reverse) proxy, fixing either component is sufficient to mitigate this issue.

### Credits

Reported by Jeppe Bonde Weikop on 2025-01-09.

---

_Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai_
