CVE-2026-49855 Overview
CVE-2026-49855 is a denial-of-service vulnerability in Tornado, a Python web framework and asynchronous networking library. Versions prior to 6.5.6 fail to enforce an overall limit on accumulated decompressed data in gzip handling routines. A malicious server accessed by SimpleAsyncHTTPClient, or an HTTPServer configured with decompress_request=True, can force the affected process to consume effectively unlimited memory. The flaw is classified under [CWE-409] (Improper Handling of Highly Compressed Data). Tornado version 6.5.6 addresses the issue by propagating max_body_size into the gzip message delegate.
Critical Impact
A malicious peer can trigger unbounded memory allocation in Tornado clients and servers, exhausting host resources and causing service outages.
Affected Products
- Tornado versions prior to 6.5.6 (client side via SimpleAsyncHTTPClient)
- Tornado versions prior to 6.5.6 (server side with decompress_request=True)
- Python applications embedding vulnerable Tornado releases
Discovery Timeline
- 2026-07-14 - CVE-2026-49855 published to NVD
- 2026-07-16 - Last updated in NVD database
Technical Details for CVE-2026-49855
Vulnerability Analysis
Tornado's HTTP/1 connection handling supports transparent gzip decompression through the _GzipMessageDelegate class in tornado/http1connection.py. The delegate processes incoming compressed data in bounded chunks, applying chunk_size as a per-chunk decompression limit. However, prior to 6.5.6, no aggregate cap tracked the total volume of decompressed bytes across all chunks. An attacker delivering a highly compressed gzip stream (a compression bomb) can force the delegate to expand data indefinitely while the process accumulates it in memory. The condition maps to [CWE-409], improper handling of highly compressed data.
Root Cause
The root cause is a missing aggregate size enforcement in the gzip decompression pipeline. _GzipMessageDelegate received only the per-chunk limit and ignored the connection's max_body_size setting. As a result, repeated chunk decompression bypassed the intended body size ceiling.
Attack Vector
A remote attacker exploits the flaw by serving crafted gzip responses to Tornado clients using SimpleAsyncHTTPClient, or by sending gzip-encoded requests to a Tornado HTTPServer running with decompress_request=True. No authentication or user interaction is required, and the attack is delivered over the network.
# Security patch in tornado/http1connection.py
# been read. The result is true if the stream is still open.
"""
if self.params.decompress:
- delegate = _GzipMessageDelegate(delegate, self.params.chunk_size)
+ delegate = _GzipMessageDelegate(
+ delegate, self.params.chunk_size, self._max_body_size
+ )
return self._read_message(delegate)
async def _read_message(self, delegate: httputil.HTTPMessageDelegate) -> bool:
Source: GitHub Tornado Commit ff808b3. The patch passes self._max_body_size into _GzipMessageDelegate so the delegate can abort decompression when accumulated output exceeds the configured limit.
Detection Methods for CVE-2026-49855
Indicators of Compromise
- Sudden, sustained memory growth in Python processes hosting Tornado applications without a corresponding increase in request throughput.
- Repeated inbound or outbound HTTP transfers with Content-Encoding: gzip and unusually high decompression ratios.
- Tornado worker crashes, OOM-killer events, or container restarts correlated with gzip-encoded traffic.
Detection Strategies
- Inventory Python environments for Tornado versions below 6.5.6 using pip list output or software composition analysis tooling.
- Inspect application code for SimpleAsyncHTTPClient usage and HTTPServer(..., decompress_request=True) configurations.
- Monitor HTTP proxy or WAF logs for requests and responses with anomalous compression ratios exceeding typical baselines.
Monitoring Recommendations
- Alert on Linux oom_kill events and cgroup memory pressure metrics for containers running Tornado services.
- Track resident set size (RSS) growth per Tornado worker and correlate spikes with request identifiers for gzip payloads.
- Ingest application and system telemetry into a centralized analytics platform to correlate memory exhaustion with upstream client identifiers.
How to Mitigate CVE-2026-49855
Immediate Actions Required
- Upgrade Tornado to version 6.5.6 or later in all Python environments, including container base images and CI build pipelines.
- Audit services that call untrusted HTTP endpoints via SimpleAsyncHTTPClient and prioritize patching internet-facing components.
- For servers that must accept gzip request bodies, verify max_body_size is set to a value appropriate for the workload.
Patch Information
The fix is delivered in Tornado 6.5.6. See the GitHub Security Advisory GHSA-mgf9-4vpg-hj56, the merged Tornado Pull Request #3626, and the corresponding upstream commit ff808b3. The patch propagates max_body_size into _GzipMessageDelegate so accumulated decompressed output is capped.
Workarounds
- Disable request decompression by setting decompress_request=False on HTTPServer until upgrades complete.
- Avoid using SimpleAsyncHTTPClient against untrusted servers, or place a reverse proxy that strips or validates Content-Encoding: gzip in front of Tornado services.
- Enforce OS or container memory limits so a single Tornado worker cannot exhaust host resources.
# Upgrade Tornado to the patched release
pip install --upgrade 'tornado>=6.5.6'
# Verify the installed version
python -c "import tornado; print(tornado.version)"
# Optional: pin the fixed version in requirements.txt
echo 'tornado>=6.5.6' >> requirements.txt
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

