Where
-Infinity
0
Severity
5.3
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L

Summary

When Tornado reads an HTTP/1.1 body that uses chunked transfer encoding, it processes all chunks that have already arrived without yielding to the event loop. A client can send a body made of millions of 1-byte chunks, which blocks the event loop (and therefore every other connection served by that process) for the entire time it takes to parse the body. A body near the default maxbodysize of 100 MB can block the process for close to a minute, and the attacker can repeat or parallelize these requests.

Bodies made of tiny chunks also consumed far more memory than their size: a handler that does not use @streamrequestbody stored each chunk as a separate object, using roughly 20 times as much memory as the bytes received.

Impact

All Tornado HTTP servers are affected when they receive a request body for a handler that reads it, which includes any handler that does not reject the request before the body is read. No authentication is required. Lowering maxbodysize reduces the maximum blocking time and memory use for each request but does not remove the issue.

SimpleAsyncHTTPClient is affected in the same way when it reads a response from a malicious server.

Patches

Fixed in Tornado 6.6. Tornado now yields to the event loop periodically while reading any body, combines small chunks before passing them to datareceived, and stores non-streaming bodies more compactly.

Applications using @streamrequestbody should note that the pieces passed to datareceived no longer correspond to HTTP chunk boundaries.

Workarounds

- Run Tornado behind a reverse proxy that buffers request bodies and forwards them with a Content-Length header instead of chunked encoding. - Lower maxbodysize (for the whole server or for individual handlers) to limit the impact of each request.

Credit

Reported by uttej-badwane.

1 / 3
Source: GitHub
First published (updated )
Severity
5.3
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L

Summary

Tornado's HTTP header parser takes quadratic time (O(n²)) when a header value is continued across many "obsolete line folding" (obs-fold) lines. An unauthenticated attacker can send a request whose header block is mostly short continuation lines. Parsing it uses a large amount of CPU on the IOLoop thread and blocks every other connection that process is serving.

This issue is closely related to CVE-2025-67725 (GHSA-c98p-7wgm-6p64). The fix for that advisory covered repeated headers but not line-folded continuations.

Impact

All Tornado HTTP servers are affected. Header parsing runs before any application code, so no authentication or particular handler is required.

How bad it gets depends on maxheadersize:

- Default (64 KB): each malicious request blocks the event loop for tens of milliseconds. Repeated requests can degrade service. - Raised maxheadersize: the cost grows with the square of the header size. A single 1 MB request can block the process for several seconds.

Only availability is affected. Confidentiality and integrity are not.

Patches

Fixed in Tornado 6.6 by removing support for obsolete line folding completely; header lines that begin with whitespace are now rejected.

Workarounds

- Keep maxheadersize at its default value or lower it. This limits the impact but doesn't remove it. - Run Tornado behind a reverse proxy that rejects or normalizes obsolete line folding before forwarding requests.

Credit

Reported by @manus-pi.

1 / 3
Source: GitHub
First published (updated )
Severity
6.9
AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Tornado before 6.5.9 fails to limit the number of query string fields in HTTPServerRequest.init, allowing remote attackers to cause event-loop stalling by sending requests with thousands of query parameters. Attackers can send unauthenticated GET requests with unbounded query-string field counts to degrade response times for all clients sharing the same IOLoop.

First published (updated )
Severity
8.2
Path Traversal
AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N

Tornado before 6.5.9 contains a path traversal vulnerability in StaticFileHandler that follows symbolic links inside the static root without confirming the resolved target stays within it. When a symlink pointing outside the static directory exists inside it, unauthenticated attackers can request it to read files such as configuration files, private keys, and application secrets accessible to the process user.

1 / 2
Source: Ubuntu
First published (updated )
Severity
8.2
EPSS
0.21%
Infoleak
AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N

Tornado before 6.5.7 contains a credential leak vulnerability in CurlAsyncHTTPClient where pycurl handles are reused across requests without proper state clearing. Attackers can obtain sensitive credentials by issuing requests through the same client instance, allowing TLS certificates or proxy authentication to persist across unintended requests.

1 / 2
Source: Ubuntu
First published (updated )
Severity
4

In Tornado before 6.5.5, cookie attribute injection could occur because the domain, path, and samesite arguments to .RequestHandler.setcookie were not checked for crafted characters.

First published (updated )
Severity
4

Tornado is a Python web framework and asynchronous networking library. In versions of Tornado prior to 6.5.5, the only limit on the number of parts in multipart/form-data is the maxbodysize setting (default 100MB). Since parsing occurs synchronously on the main thread, this creates the possibility of denial-of-service due to the cost of parsing very large multipart bodies with many parts. This vulnerability is fixed in 6.5.5.

First published (updated )
Severity
8.7
EPSS
0.07%
AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

In versions of Tornado prior to 6.5.5, the only limit on the number of parts in multipart/form-data is the maxbodysize setting (default 100MB). Since parsing occurs synchronously on the main thread, this creates the possibility of denial-of-service due to the cost of parsing very large multipart bodies with many parts.

Tornado 6.5.5 introduces new limits on the size and complexity of multipart bodies, including a default limit of 100 parts per request. These limits are configurable if needed; see tornado.httputil.ParseMultipartConfig. It is also now possible to disable multipart/form-data parsing entirely if it is not required for the application.

1 / 2
Source: GitHub
First published (updated )
Severity
4

Tornado is a Python web framework and asynchronous networking library. In versions 6.5.2 and below, a single maliciously crafted HTTP request can block the server's event loop for an extended period, caused by the HTTPHeaders.add method. The function accumulates values using string concatenation when the same header name is repeated, causing a Denial of Service (DoS). Due to Python string immutability, each concatenation copies the entire string, resulting in O(n²) time complexity. The severity can vary from high if maxheadersize has been increased from its default, to low if it has its default value of 64KB. This issue is fixed in version 6.5.3.

First published (updated )
Severity
4

Tornado is a Python web framework and asynchronous networking library. Versions 6.5.2 and below use an inefficient algorithm when parsing parameters for HTTP header values, potentially causing a DoS. The parseparam function in httputil.py is used to parse specific HTTP header values, such as those in multipart/form-data and repeatedly calls string.count() within a nested loop while processing quoted semicolons. If an attacker sends a request with a large number of maliciously crafted parameters in a Content-Disposition header, the server's CPU usage increases quadratically (O(n²)) during parsing. Due to Tornado's single event loop architecture, a single malicious request can cause the entire server to become unresponsive for an extended period. This issue is fixed in version 6.5.3.

First published (updated )
Severity
7.5
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Summary

The parseparam function in Tornado's httputil.py is used to parse specific HTTP header values, such as those in multipart/form-data. This function uses an inefficient algorithm that repeatedly calls string.count() within a nested loop while processing quoted semicolons (e.g., param=";").

As a result, if an attacker sends a request with a large number of maliciously crafted parameters in a Content-Disposition header, the server's CPU usage increases quadratically (O(n²)) during parsing. Due to Tornado's single event loop architecture, a single malicious request can cause the entire server to become unresponsive for an extended period, leading to a Denial of Service (DoS).

Severity: High

1 / 2
Source: GitHub
First published (updated )
Severity
7.5
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Summary

The HTTPHeaders.add method in Tornado accumulates values using string concatenation when the same header name is repeated. Due to Python string immutability, each concatenation copies the entire string, resulting in O(n²) time complexity.

Given Tornado's single event loop architecture, a single maliciously crafted HTTP request can block the server's event loop for an extended period, causing a Denial of Service (DoS).

Severity: High if maxheadersize has been increased from its default, low if it has its default value of 64KB.

1 / 2
Source: GitHub
First published (updated )
Severity
6.1
XSS, CSRF
AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N

Header injection and XSS via reason argument

Summary

The reason argument (used by both RequestHandler.setstatus and tornado.web.HTTPError is designed to allow applications to pass custom "reason" phrases (the "Not Found" in HTTP/1.1 404 Not Found) to the HTTP status line (mainly for non-standard status codes). Vulnerabilities exist in Tornado versions prior to 6.5.3 if untrusted data is passed as the reason argument.

Details

In vulnerable versions, the supplied reason phrase is used unescaped in HTTP headers (where it could be used for header injection) or in HTML in the default error page (where it could be used for XSS).

Impact

Type: Reflected Cross-Site Scripting (CWE-79) in default error page, or header injection (CWE-644) Actors: Remote attacker who can cause the application to raise HTTPError/setstatus with an attacker-controlled reason (e.g., via query parameter used by developer). Effect: Execution of arbitrary JavaScript in victims' browsers when they view the error page — possible session token theft, CSRF escalation, UI spoofing, or other client-side attacks depending on context. Scope: Only applications that explicitly reflect untrusted input into reason are affected.

Mitigation

Aside from upgrading to Tornado 6.5.3 or newer, the vulnerability can be mitigated by not using untrusted data for the reason argument. In the intended use case the reason argument would generally be a string literal and not derived from user input. Also, the reason argument is rarely required (reason phrases are not used at all in HTTP/2) and can generally be omitted.

For a general-purpose error message in HTTPError, consider using the logmessage argument instead of reason.

1 / 2
Source: GitHub
First published (updated )

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203