Inconsistent interpretation of `Content-Length` vs. `Transfer-Encoding` in aiohttp
Description
aiohttp is an asynchronous HTTP client/server framework for asyncio and Python. Affected versions of aiohttp have a security vulnerability regarding the inconsistent interpretation of the http protocol. HTTP/1.1 is a persistent protocol, if both Content-Length(CL) and Transfer-Encoding(TE) header values are present it can lead to incorrect interpretation of two entities that parse the HTTP and we can poison other sockets with this incorrect interpretation. A possible Proof-of-Concept (POC) would be a configuration with a reverse proxy(frontend) that accepts both CL and TE headers and aiohttp as backend. As aiohttp parses anything with chunked, we can pass a chunked123 as TE, the frontend entity will ignore this header and will parse Content-Length. The impact of this vulnerability is that it is possible to bypass any proxy rule, poisoning sockets to other users like passing Authentication Headers, also if it is present an Open Redirect an attacker could combine it to redirect random users to another website and log the request. This vulnerability has been addressed in release 3.8.0 of aiohttp. Users are advised to upgrade. There are no known workarounds for this vulnerability.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
aiohttpPyPI | < 3.8.0 | 3.8.0 |
Affected products
1Patches
1f016f0680e4aRaise '400: Content-Length can't be present with Transfer-Encoding' if both Content-Length and Transfer-Encoding are sent by peer (#6182)
3 files changed · +25 −3
aiohttp/http_parser.py+10 −2 modified@@ -28,6 +28,7 @@ from .base_protocol import BaseProtocol from .helpers import NO_EXTENSIONS, BaseTimerContext from .http_exceptions import ( + BadHttpMessage, BadStatusLine, ContentEncodingError, ContentLengthError, @@ -489,8 +490,15 @@ def parse_headers( # chunking te = headers.get(hdrs.TRANSFER_ENCODING) - if te and "chunked" in te.lower(): - chunked = True + if te is not None: + te_lower = te.lower() + if "chunked" in te_lower: + chunked = True + + if hdrs.CONTENT_LENGTH in headers: + raise BadHttpMessage( + "Content-Length can't be present with Transfer-Encoding", + ) return (headers, raw_headers, close_conn, encoding, upgrade, chunked)
CHANGES/6182.bugfix+1 −0 added@@ -0,0 +1 @@ +Raise ``400: Content-Length can't be present with Transfer-Encoding`` if both ``Content-Length`` and ``Transfer-Encoding`` are sent by peer by both C and Python implementations
tests/test_http_parser.py+14 −1 modified@@ -291,7 +291,20 @@ def test_request_chunked(parser) -> None: assert isinstance(payload, streams.StreamReader) -def test_conn_upgrade(parser) -> None: +def test_request_te_chunked_with_content_length(parser: Any) -> None: + text = ( + b"GET /test HTTP/1.1\r\n" + b"content-length: 1234\r\n" + b"transfer-encoding: chunked\r\n\r\n" + ) + with pytest.raises( + http_exceptions.BadHttpMessage, + match="Content-Length can't be present with Transfer-Encoding", + ): + parser.feed_data(text) + + +def test_conn_upgrade(parser: Any) -> None: text = ( b"GET /test HTTP/1.1\r\n" b"connection: upgrade\r\n"
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
7- github.com/advisories/GHSA-xx9p-xxvh-7g8jghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2023-47641ghsaADVISORY
- github.com/aio-libs/aiohttp/commit/f016f0680e4ace6742b03a70cb0382ce86abe371ghsax_refsource_MISCWEB
- github.com/aio-libs/aiohttp/releases/tag/v3.8.0ghsaWEB
- github.com/aio-libs/aiohttp/security/advisories/GHSA-xx9p-xxvh-7g8jghsax_refsource_CONFIRMWEB
- github.com/pypa/advisory-database/tree/main/vulns/aiohttp/PYSEC-2023-247.yamlghsaWEB
- lists.debian.org/debian-lts-announce/2025/02/msg00002.htmlghsaWEB
News mentions
0No linked articles in our index yet.