NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
PyPI · #262 most downloaded on PyPI
Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed.
Last release 12 days ago
22 Sep 2026
Ships fairly regularly
a new release about every 3 months
Most releases are documented
notes for 40 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
16 years old
87 releases · first in 2010
Nothing published for this version
The allowed_symlink_directory argument of StaticFileHandler may now be a list of directories instead of just a single directory. This feature has been
Bug fixes
`tornado.web`
allowed_symlink_directory argument of StaticFileHandler may now be a listThe allowed_symlink_directory argument of StaticFileHandler may now be a list of directories instead of just a single directory. This feature has been adjusted to improve compatibility with Jupyter, which would fail to load with Tornado 6.5.9.
One column per quarter.
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="
Security fixes
- `.StaticFileHandler` no longer follows symlinks outside of the static root directory.
Applications that wish to continue the previous behavior may set the new argument
``allowed_symlink_directory`` to the directory (an ancestor of the static root) that
should be used for symlink validation. Thanks to `afldl <https://github.com/afldl>`_ and
`iaokhut-from-NightWolf-Team <https://github.com/iaokhut-from-NightWolf-Team>`_ for
reporting this issue.
- ``curl_httpclient`` has a new ``max_body_size`` argument (default 100MB, same as
for ``simple_httpclient``). This limit is enforced on all requests, whether or not
``streaming_callback`` is used. ``curl_httpclient`` now also controls its memory usage
when decompressing response bodies. Thanks to `afldl <https://github.com/afldl>`_,
`iaohkut-from-NightWolf-Team <https://github.com/iaohkut-from-NightWolf-Team>`_, and
`aoto-tech <https://github.com/aoto-tech>`_ for reporting this issue.
- ``simple_httpclient`` now correctly applies the ``max_body_size`` limit to responses
using HTTP/1.0 format (no ``Content-Length`` or ``Transfer-Encoding``). Previously it
silently truncated such responses at ``max_buffer_size`` instead. Thanks to
`afldl <https://github.com/afldl>`_ for reporting this issue.
- ``simple_httpclient`` now rejects responses that use more than 10 ``100 Continue`` responses,
which could previously cause stack overflow errors. Thanks to `afldl <https://github.com/afldl>`_
for reporting this issue.
- The limit ``ParseBodyConfig.urlencoded.max_argument`` is now applied to URL arguments
in addition to ``POST`` bodies. Thanks to
`iaohkut-from-NightWolf-Team <https://github.com/iaohkut-from-NightWolf-Team>`_,
`afldl <https://github.com/afldl>`_, and `manus-pi <https://github.com/manus-pi>`_
for reporting this issue.
Bug fixes
~~~~~~~~~
`tornado.iostream`
.IOStream.read_until_close now reports errors correctly when a stream is closed due to.IOStream), since some platforms report a clean shutdown by the peer this way..StaticFileHandler no longer follows symlinks outside of the static root directory. Applications that wish to continue the previous behavior may set the new argument allowed_symlink_directory to the directory (an ancestor of the static root) that should be used for symlink validation. Thanks to Yasha-ops and iaohkut-from-NightWolf-Team for reporting this issue.
curl_httpclient has a new max_body_size argument (default 100MB, same as for simple_httpclient). This limit is enforced on all requests, whether or not streaming_callback is used. curl_httpclient now also controls its memory usage when decompressing response bodies. Thanks to afldl, iaohkut-from-NightWolf-Team, and aoto-tech for reporting this issue.
simple_httpclient now correctly applies the max_body_size limit to responses using HTTP/1.0 format (no Content-Length or Transfer-Encoding). Previously it silently truncated such responses at max_buffer_size instead. Thanks to afldl for reporting this issue.
simple_httpclient now rejects responses that use more than 10 100 Continue responses, which could previously cause stack overflow errors. Thanks to afldl for reporting this issue.
The limit ParseBodyConfig.urlencoded.max_argument is now applied to URL arguments in addition to POST bodies. Thanks to iaohkut-from-NightWolf-Team, afldl, and manus-pi for reporting this issue.
.IOStream.read_until_close now reports errors correctly when a stream is closed due to an error or exceeds a memory limit. Previously it would report a successful read of whatever was in the buffer. Connection resets are still treated as a normal close (as they are elsewhere in .IOStream), since some platforms report a clean shutdown by the peer this way.
The deprecated mixed-case arguments to .RequestHandler.set_cookie now enforce the same restrictions on invalid characters that were introduced in Torn…
Security fixes
- Form-encoded ``POST`` bodies are now subject to a limit of 1000 arguments by default. This
prevents a CPU and memory denial of service attack. This limit can be overridden via the
`.set_parse_body_config` function. Thanks to `Arpit Jain <https://github.com/arpitjain099>`_
for reporting this issue.
- Multipart parsing now rejects requests with an excessive number of parts earlier in the parsing
process, limiting memory consumption. Thanks to `afldl <https://github.com/afldl>`_ for
reporting this issue.
- The deprecated mixed-case arguments to `.RequestHandler.set_cookie` now enforce the same
restrictions on invalid characters that were introduced in Tornado 6.5.5 for the standard
lowercase arguments. Thanks to `sec-reex <https://github.com/sec-reex>`_ and
`Arpit Jain <https://github.com/arpitjain099>`_ for reporting this issue.
Deprecations
~~~~~~~~~~~~
- The `.OpenIdMixin` class is deprecated and will be removed in Tornado 6.7. OpenID 2.0 is no
longer widely supported by identity providers.
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="
Security fixes
- ``CurlAsyncHTTPClient`` now fully resets the curl object before reusing it. This prevents
incorrectly reusing options from a previous request, specifically including client SSL and
credentials used for accessing proxies. Thanks to `Koh Jun Sheng <https://github.com/seankohjs>`_
for reporting this issue.
CurlAsyncHTTPClient now fully resets the curl object before reusing it. This prevents incorrectly reusing options from a previous request, specifically including client SSL and credentials used for accessing proxies. Thanks to Koh Jun Sheng for reporting this issue.
CurlAsyncHTTPClient has been updated to use non-deprecated APIs, avoiding deprecation warnings with recent versions of pycurl.">
Security fixes
- ``SimpleAsyncHTTPClient`` now strips the ``Authorization`` and ``Cookie`` headers from the request
when following a redirect to a different origin. This matches the default behavior of
``CurlAsyncHTTPClient``. Applications that need different behavior here can set
``follow_redirects=False`` and handle redirects manually. Thanks to [Yannick
Wang](https://github.com/noobone123) for being first to report this issue, as well as additional
reporters [Kai Aizen](https://github.com/SnailSploit), [HunSec](https://github.com/0xHunSec), and
[Thai Son Dinh](https://github.com/sondt99).
- ``SimpleAsyncHTTPClient`` now enforces ``max_body_size`` on the decompressed size of the response,
rather than the compressed size. This prevents a denial-of-service attack via a very large
compressed response. Thanks to [Yuichiro Kedashiro](https://github.com/yuui25) for reporting this
issue.
- Fixed a bug in the C extension that could have read up to three bytes past the end of an input
array. Thanks to [Thai Son Dinh](https://github.com/sondt99) for reporting this issue.
- ``OpenIDMixin`` has improved parsing for the ``check_authentication`` response. Thanks to
[Yannick Wang](https://github.com/noobone123) for reporting this issue.
Bug fixes
~~~~~~~~~
- ``CurlAsyncHTTPClient`` has been updated to use non-deprecated APIs, avoiding deprecation
warnings with recent versions of ``pycurl``.
SimpleAsyncHTTPClient now strips the Authorization and Cookie headers from the request when following a redirect to a different origin. This matches the default behavior of CurlAsyncHTTPClient. Applications that need different behavior here can set follow_redirects=False and handle redirects manually. Thanks to Yannick Wang for being first to report this issue, as well as additional reporters Kai Aizen, HunSec, and Thai Son Dinh. CVE-2026-49853
SimpleAsyncHTTPClient now enforces max_body_size on the decompressed size of the response, rather than the compressed size. This prevents a denial-of-service attack via a very large compressed response. Thanks to Yuichiro Kedashiro for reporting this issue. CVE-2026-49855
Fixed a bug in the C extension that could have read up to three bytes past the end of an input array. Thanks to Thai Son Dinh for reporting this issue. CVE-2026-49854
OpenIDMixin has improved parsing for the check_authentication response. Thanks to Yannick Wang for reporting this issue.
CurlAsyncHTTPClient has been updated to use non-deprecated APIs, avoiding deprecation warnings with recent versions of pycurl.
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="
Security fixes
- ``multipart/form-data`` requests are now limited to 100 parts by default, to prevent a
denial-of-service attack via very large requests with many parts. This limit is configurable
via `tornado.httputil.ParseMultipartConfig`. Multipart parsing can also be disabled completely
if not required for the application. Thanks to [0x-Apollyon](https://github.com/0x-Apollyon) and
[bekkaze](https://github.com/bekkaze) for reporting this issue.
- The ``domain``, ``path``, and ``samesite`` arguments to `.RequestHandler.set_cookie` are now
validated for illegal characters, which could be abused to inject other attributes on the cookie.
Thanks to Dhiral Vyas (Praetorian) for reporting this issue.
- Carriage return characters are no longer accepted in ``multipart/form-data`` headers. Thanks to
[sergeykochanov](https://github.com/sergeykochanov) for reporting this issue.
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="
Bug fixes
- The ``in`` operator for ``HTTPHeaders`` was incorrectly case-sensitive, causing
lookups to fail for headers with different casing than the original header name.
This was a regression in version 6.5.3 and has been fixed to restore the intended
case-insensitive behavior from version 6.5.2 and earlier.
The in operator for HTTPHeaders was incorrectly case-sensitive, causing lookups to fail for headers with different casing than the original header name. This was a regression in version 6.5.3 and has been fixed to restore the intended case-insensitive behavior from version 6.5.2 and earlier.
…when parsing multipart/form-data request bodies. CVE-2025-67726 <https://github.com/tornadoweb/tornado/security/advisories/GHSA-jhmp-mqwm-3gq8>_ Thank…
Security fixes
- Fixed a denial-of-service vulnerability involving quadratic computation when parsing
``multipart/form-data`` request bodies.
`CVE-2025-67726 <https://github.com/tornadoweb/tornado/security/advisories/GHSA-jhmp-mqwm-3gq8>`_
Thanks to `Finder16 <https://github.com/Finder16>`_ for reporting this issue.
- Fixed a denial-of-service vulnerability involving quadratic computation when parsing repeated HTTP
headers.
`CVE-2025-67725 <https://github.com/tornadoweb/tornado/security/advisories/GHSA-c98p-7wgm-6p64>`_.
Thanks to `Finder16 <https://github.com/Finder16>`_ for reporting this issue.
- Fixed a header injection and XSS vulnerability involving the ``reason`` argument to
`.RequestHandler.set_status` and `tornado.web.HTTPError`.
`CVE-2025-67724 <https://github.com/tornadoweb/tornado/security/advisories/GHSA-pr2v-jx2c-wg9f>`_.
Thanks to `Finder16 <https://github.com/Finder16>`_ and
`Cheshire1225 <https://github.com/Cheshire1225>`_ for reporting this issue.
Demo changes
~~~~~~~~~~~~
- Several demo applications bundled with the Tornado repo (``blog``, ``chat``, ``facebook``) had an
open redirect vulnerability which has been fixed. This is not covered by a CVE or security
advisory since the demo applications are not included as a part of the Tornado package when
installed, but developers who have copied code from these demos may which to review their own
applications for open redirects. Thanks to `J1vvoo <https://github.com/J1vvoo>`_ for reporting this
issue.
- The ``s3server`` demo application contained some path traversal vulnerabilities. Since this demo
application was not demonstrating any interesting aspects of Tornado, it has been deleted rather
than being fixed. Thanks to `J1vvoo <https://github.com/J1vvoo>`_ for reporting this issue.
Fixed a denial-of-service vulnerability involving quadratic computation when parsing multipart/form-data request bodies. CVE-2025-67726 Thanks to Finder16 for reporting this issue.
Fixed a denial-of-service vulnerability involving quadratic computation when parsing repeated HTTP headers. CVE-2025-67725. Thanks to Finder16 for reporting this issue.
Fixed a header injection and XSS vulnerability involving the reason argument to .RequestHandler.set_status and tornado.web.HTTPError. CVE-2025-67724. Thanks to Finder16 and Cheshire1225 for reporting this issue.
Several demo applications bundled with the Tornado repo (blog, chat, facebook) had an open redirect vulnerability which has been fixed. This is not covered by a CVE or security advisory since the demo applications are not included as a part of the Tornado package when installed, but developers who have copied code from these demos may which to review their own applications for open redirects. Thanks to J1vvoo for reporting this issue.
The s3server demo application contained some path traversal vulnerabilities. Since this demo application was not demonstrating any interesting aspects of Tornado, it has been deleted rather than being fixed. Thanks to J1vvoo for reporting this issue.
Restored the host argument to .HTTPServerRequest. This argument is deprecated and will be removed in the future, but its removal with no warning in 6.…
Bug fixes
- Fixed a bug that resulted in WebSocket pings not being sent at the configured interval.
- Improved logging for invalid ``Host`` headers. This was previouisly logged as an uncaught
exception with a stack trace, now it is simply a 400 response (logged as a warning in the
access log)
- Restored the ``host`` argument to ``.HTTPServerRequest``. This argument is deprecated
and will be removed in the future, but its removal with no warning in 6.5.0 was a mistake.
- Removed a debugging print statement that was left in the code.
- Improved type hints for ``gen.multi``.
Fixed a bug that resulted in WebSocket pings not being sent at the configured interval.
Improved logging for invalid Host headers. This was previously logged as an uncaught exception with a stack trace, now it is simply a 400 response (logged as a warning in the access log).
Restored the host argument to .HTTPServerRequest. This argument is deprecated and will be removed in the future, but its removal with no warning in 6.5.0 was a mistake.
Removed a debugging print statement that was left in the code.
Improved type hints for gen.multi.
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="
Bug fixes
- Fixed a bug in ``multipart/form-data`` parsing that could incorrectly reject filenames containing
characters above U+00FF (i.e. most characters outside the Latin alphabet).
Fixed a bug in multipart/form-data parsing that could incorrectly reject filenames containing characters above U+00FF (i.e. most characters outside the Latin alphabet).
Prepare for release 6.5b1
Prepare for release 6.5b1
Nothing published for this version
…and block the event loop. This change fixes CVE-2024-7592.
Parsing of the cookie header is now much more efficient. The older algorithm sometimes had quadratic performance which allowed for a denial-of-service attack in which the server would spend excessive CPU time parsing cookies and block the event loop. This change fixes CVE-2024-7592.
Security Improvements ~~~~~~~~~~~~~~~~~~~~~
Parsing of the Transfer-Encoding header is now stricter. Unexpected transfer-encoding values were previously ignored and treated as the HTTP/1.0 default of read-until-close. This can lead to framing issues with certain proxies. We now treat any unexpected value as an error.
Handling of whitespace in headers now matches the RFC more closely. Only space and tab characters are treated as whitespace and stripped from the beginning and end of header values. Other unicode whitespace characters are now left alone. This could also lead to framing issues with certain proxies.
tornado.curl_httpclient now prohibits carriage return and linefeed headers in HTTP headers (matching the behavior of simple_httpclient). These characters could be used for header injection or request smuggling if untrusted data were used in headers.
.SSLIOStream now understands changes to error codes from OpenSSL 3.2. The main result of this change is to reduce the noise in the logs for certain errors.
simple_httpclient now prohibits carriage return characters in HTTP headers. It had previously prohibited only linefeed characters.
.AsyncTestCase subclasses can now be instantiated without being associated with a test method. This improves compatibility with test discovery in Pytest 8.2.
Nothing published for this version
Nothing published for this version
…RFCs) to avoid potential request-smuggling vulnerabilities when deployed behind certain proxies.
The Content-Length header and chunked Transfer-Encoding sizes are now parsed more strictly (according to the relevant RFCs) to avoid potential request-smuggling vulnerabilities when deployed behind certain proxies.
Fixed an open redirect vulnerability in StaticFileHandler under certain configurations.
Fixed an open redirect vulnerability in StaticFileHandler under certain configurations.
.RequestHandler.set_cookie once again accepts capitalized keyword arguments for backwards compatibility. This is deprecated and in Tornado 7.0 only lo…
.RequestHandler.set_cookie once again accepts capitalized keyword arguments for backwards compatibility. This is deprecated and in Tornado 7.0 only lowercase arguments will be accepted.
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
General changes ~~~~~~~~~~~~~~~
Binary wheels are now available for Python 3.8 on Windows. Note that it is still necessary to use asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) for this platform/version.
Fixed an issue in .IOStream (introduced in 6.0.0) that resulted in StreamClosedError being incorrectly raised if a stream is closed mid-read but there is enough buffered data to satisfy the read.
.AnyThreadEventLoopPolicy now always uses the selector event loop on Windows.
.gen.with_timeout always treats asyncio.CancelledError as a quiet_exception (this improves compatibility with Python 3.8, which changed CancelledError
.gen.with_timeout always treats asyncio.CancelledError as a quiet_exception (this improves compatibility with Python 3.8, which changed CancelledError to a BaseException).
IOStream now checks for closed streams earlier, avoiding spurious logged errors in some situations (mainly with websockets).
.WebSocketHandler.set_nodelay works again.
.WebSocketHandler.set_nodelay works again.
Accessing HTTPResponse.body now returns an empty byte string instead of raising ValueError for error responses that don't have a body (it returned None in this case in Tornado 5).
Fixed issues with type annotations that caused errors while importing Tornado on Python 3.5.2.
Fixed issues with type annotations that caused errors while importing Tornado on Python 3.5.2.
Nothing published for this version
Nothing published for this version
Nothing published for this version
Fixed an case in which the .Future returned by .RequestHandler.finish could fail to resolve.
Fixed an case in which the .Future returned by .RequestHandler.finish could fail to resolve.
The .TwitterMixin.authenticate_redirect method works again.
Improved error handling in the tornado.auth module, fixing hanging requests when a network or other error occurs.
Nothing published for this version
Nothing published for this version
Fixed a memory leak when .IOLoop objects are created and destroyed.
Fixed a memory leak when .IOLoop objects are created and destroyed.
If .AsyncTestCase.get_new_ioloop returns a reference to a preexisting event loop (typically when it has been overridden to return .IOLoop.current()), the test's tearDown method will not close this loop.
Fixed a confusing error message when the synchronous .HTTPClient fails to initialize because an event loop is already running.
.PeriodicCallback no longer executes twice in a row due to backwards clock adjustments.
This release restores support for versions of Python 3.4 prior to 3.4.4. This is important for compatibility with Debian Jessie which has 3.4.2 as its
This release restores support for versions of Python 3.4 prior to 3.4.4. This is important for compatibility with Debian Jessie which has 3.4.2 as its version of Python 3.
Nothing published for this version
Nothing published for this version
Nothing published for this version
tornado.curl_httpclient ~~~~~~~~~~~~~~~~~~~~~~~~~
Improved debug logging on Python 3.
Content-Length and Transfer-Encoding headers are no longer sent with 1xx or 204 responses (this was already true of 304 responses).
Reading chunked requests no longer leaves the connection in a broken state.
Writing a memoryview can no longer result in "BufferError: Existing exports of data: object cannot be re-sized".
Duplicate option names are now detected properly whether they use hyphens or underscores.
.AsyncHTTPTestCase.fetch now uses 127.0.0.1 instead of localhost, improving compatibility with systems that have partially-working ipv6 stacks.
It is no longer allowed to send a body with 1xx or 204 responses.
Requests with invalid websocket headers now get a response with status code 400 instead of a closed connection.
Tornado now sets the FD_CLOEXEC flag on all file descriptors it creates. This prevents hanging client connections and resource leaks when the tornado.
Tornado now sets the FD_CLOEXEC flag on all file descriptors it creates. This prevents hanging client connections and resource leaks when the tornado.autoreload module (or Application(debug=True)) is used.
Improved detection of libraries for colorized logging.
Improved detection of libraries for colorized logging.
.url_concat once again treats None as equivalent to an empty sequence.
Nothing published for this version
Nothing published for this version
Nothing published for this version
The tornado.auth module has been updated for compatibility with a change to Facebook's access_token endpoint. _
The tornado.auth module has been updated for compatibility with a change to Facebook's access_token endpoint.
A difference in cookie parsing between Tornado and web browsers (especially when combined with Google Analytics) could allow an attacker to set arbitr
A difference in cookie parsing between Tornado and web browsers (especially when combined with Google Analytics) could allow an attacker to set arbitrary cookies and bypass XSRF protection. The cookie parser has been rewritten to fix this attack.
Cookies containing certain special characters (in particular semicolon and square brackets) are now parsed differently.
If the cookie header contains a combination of valid and invalid cookies, the valid ones will be returned (older versions of Tornado would reject the entire header for a single invalid cookie).
Fixed a regression in Tornado 4.4 which caused URL regexes containing backslash escapes outside capturing groups to be rejected.
Fixed a regression in Tornado 4.4 which caused URL regexes containing backslash escapes outside capturing groups to be rejected.
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
This release fixes a path traversal vulnerability in .StaticFileHandler, in which files whose names *started with* the static_path directory but were…
This release fixes a path traversal vulnerability in .StaticFileHandler, in which files whose names started with the static_path directory but were not actually in that directory could be accessed.
Nothing published for this version
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →