CVE-2026-115927: Event Loop Blocking and Memory Amplification in Tornado Chunked Transfer Encoding Parser
Vulnerability ID: CVE-2026-115927
CVSS Score: 5.3
Published: 2026-10-28
Tornado versions prior to 6.6.0 contain an uncontrolled resource consumption vulnerability (CWE-400) in the HTTP/1.1 chunked transfer encoding parser. When processing incoming chunked payloads that have already buffered in the socket read buffer, Tornado parses chunks in a tight synchronous loop without yielding to the event loop. Furthermore, non-streaming request handlers and SimpleAsyncHTTPClient store each chunk as a discrete Python bytes object inside a list, inducing an approximately 20-fold memory overhead for 1-byte chunks.
TL;DR
An unauthenticated remote attacker can send an HTTP/1.1 request or response with millions of 1-byte chunks to a Tornado server or client (< 6.6.0), monopolizing the Python asyncio event loop and causing approximately 20x memory amplification.
⚠️ Exploit Status: POC
Technical Details
- CVE ID: CVE-2026-115927 (GHSA-r4j5-9xpp-3985)
- CWE Classification: CWE-400 (Uncontrolled Resource Consumption) / CWE-770
- CVSS v3.1 Score: 5.3 Medium (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L)
- Attack Vector: Network (Unauthenticated HTTP/1.1 Chunked Transfer Encoding)
- Affected Component: tornado/http1connection.py, httpserver.py, web.py, simple_httpclient.py
- Security Impact: Process-wide IOLoop starvation and ~20x memory amplification
- EPSS Score: 0.384% (32.33rd percentile)
- Patched Version: Tornado 6.6.0
Affected Systems
- Tornado Web Framework (< 6.6.0)
- Tornado HTTPServer (< 6.6.0)
- Tornado SimpleAsyncHTTPClient (< 6.6.0)
-
tornado: < 6.6.0 (Fixed in:
6.6.0)
Code Analysis
Commit: ceab335
Coalesce small chunks and yield periodically in _read_chunked_body, use bytearray for body accumulation, and replace chunk CRLF assert with HTTPInputError.
--- a/tornado/http1connection.py
+++ b/tornado/http1connection.py
@@ -66,6 +66,9 @@
+# Yield to the event loop after processing this many bytes of body data
+_YIELD_THRESHOLD = 256 * 1024
+_CHUNK_YIELD_COST = 1024
...
- crlf = await self.stream.read_bytes(2)
- assert crlf == b"\r\n"
+ crlf = await read(self.stream.read_bytes(2))
+ if crlf != b"\r\n":
+ raise httputil.HTTPInputError("improperly terminated chunk")
Exploit Details
- GitHub: Unit test reproduction in tornado/test/http1connection_test.py (test_chunked_body_tiny_chunks) demonstrating event loop starvation with 1-byte chunks.
Mitigation Strategies
- Upgrade Tornado to version 6.6.0 or newer to enable periodic event loop yielding and bytearray chunk coalescing.
- Deploy an upstream HTTP reverse proxy (such as NGINX with proxy_request_buffering enabled) in front of Tornado servers to normalize and buffer incoming chunked requests.
- Configure strict max_body_size limits on HTTPServer and SimpleAsyncHTTPClient instances to cap maximum per-request resource consumption.
- Use CurlAsyncHTTPClient instead of SimpleAsyncHTTPClient when making outbound HTTP requests to untrusted third-party servers on Tornado versions prior to 6.6.0.
Remediation Steps:
- Audit application dependencies and virtual environments to identify installations of tornado < 6.6.0.
- Run
pip install --upgrade 'tornado>=6.6.0'and update requirements.txt, pyproject.toml, or lockfiles accordingly. - Verify reverse proxy configurations (e.g., NGINX, AWS ALB, HAProxy) to ensure HTTP request buffering is not disabled unless explicitly required for streaming endpoints.
- Restart all Tornado worker processes and services to load the patched library.
References
- NVD - CVE-2026-115927
- CVE.org Record - CVE-2026-115927
- GitHub Security Advisory GHSA-r4j5-9xpp-3985
- Tornado Pull Request #3773
- Tornado Patch Commit ceab33581489751a66fba8566ad6d5960d4b01c8
- Tornado v6.6.0 Release Tag
Read the full report for CVE-2026-115927 on our website for more details including interactive diagrams and full exploit analysis.
Top comments (0)