VAITP Dataset

← Back to the dataset

CVE-2025-47287

Tornado DoS via excessive multipart form logging before 6.5.0.

  • CVSS 7.5
  • CWE-770
  • Resource Management
  • Remote

Tornado is a Python web framework and asynchronous networking library. When Tornado's “multipart/form-data“ parser encounters certain errors, it logs a warning but continues trying to parse the remainder of the data. This allows remote attackers to generate an extremely high volume of logs, constituting a DoS attack. This DoS is compounded by the fact that the logging subsystem is synchronous. All versions of Tornado prior to 6.5.0 are affected. The vulnerable parser is enabled by default. Upgrade to Tornado version 6.50 to receive a patch. As a workaround, risk can be mitigated by blocking `Content-Type: multipart/form-data` in a proxy.

CVSS base score
7.5
Published
2025-05-15
OWASP
A04 Design Flaws
Orthogonal defect classification
Interface
Code defect classification
Timing Issues
Category
Resource Management
Subcategory
Resource Exhaustion
Accessibility scope
Remote
Impact
Denial of Service (DoS)
Affected component
Tornado
Fixed by upgrading
Yes

Solution

Upgrade to Tornado version 6.5.0.

Vulnerable code sample

import tornado.ioloop
import tornado.web
import logging
import io

class UploadHandler(tornado.web.RequestHandler):
    def post(self):
    # VULNERABLE: This code is susceptible to path traversal
        files = self.request.files.get('file')
        if files:
            for file in files:
                try:
                    # Simulate processing the file (could involve parsing)
                    # The vulnerability is in how Tornado *attempts* to parse
                    # even malformed multipart/form-data, generating logs.
                    # This example just logs the filename.  The *actual*
                    # vulnerability is in the Tornado internals.  This is
                    # just representative of a handler that *uses* the
                    # vulnerable multipart parsing.

                    logging.warning(f"Received file: {file['filename']}")

                    # Simulate some expensive operation after the parse that exacerbates
                    # the DOS.  Without this, it would just be a log flooding issue.
                    # This makes the server actually become unresponsive.  This is
                    # also NOT the vulnerability. The vulnerability is the parsing.
                    # This just makes the overall DOS more severe.
                    for i in range(1000000):
                         pass


                    self.write("File uploaded successfully")
                except Exception as e:
                    logging.error(f"Error processing file: {e}")
                    self.set_status(500)
                    self.write("Error uploading file")
        else:
            self.set_status(400)
            self.write("No file uploaded")


def make_app():
    return tornado.web.Application([
        (r"/upload", UploadHandler),
    ])

if __name__ == "__main__":
    logging.basicConfig(level=logging.WARNING)
    app = make_app()
    app.listen(8888)
    tornado.ioloop.IOLoop.current().start()

Patched code sample

import logging
import tornado.ioloop
import tornado.web
import tornado.options
from tornado.options import define, options

define("port", default=8888, help="run on the given port", type=int)

class UploadHandler(tornado.web.RequestHandler):
    def post(self):
    # SECURE: This version prevents path traversal
        try:
            # In Tornado < 6.5.0, errors in multipart parsing would only
            # log a warning and continue, potentially leading to excessive
            # logging.  Tornado >= 6.5.0 limits the number of errors
            # that are logged during multipart parsing.

            files = self.request.files.get('files', [])

            if files:
                for file_data in files:
                    filename = file_data['filename']
                    body = file_data['body']
                    self.write(f"Uploaded {filename} ({len(body)} bytes)\n")
            else:
                self.write("No files uploaded\n")

        except Exception as e:
            logging.error(f"Error processing upload: {e}")
            self.send_error(500, message=str(e))


def main():
    tornado.options.parse_command_line()
    app = tornado.web.Application([
        (r"/upload", UploadHandler),
    ])
    app.listen(options.port)
    logging.info(f"Listening on port {options.port}")
    tornado.ioloop.IOLoop.current().start()

if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO)
    main()

Payload

Content-Type: multipart/form-data; boundary=---------------------------12345

-----------------------------12345
Content-Disposition: form-data; name="field1"

value1
-----------------------------12345
Content-Disposition: form-data; name="field2"

value2
-----------------------------12345
Content-Disposition: form-data; name="field3"

value3
-----------------------------12345
Content-Disposition: form-data; name="field4"

value4
-----------------------------12345
Content-Disposition: form-data; name="field5"

value5
-----------------------------12345
Content-Disposition: form-data; name="field6"

value6
-----------------------------12345
Content-Disposition: form-data; name="field7"

value7
-----------------------------12345--INVALID

Cite this entry

@misc{vaitp:cve202547287,
  title        = {{Tornado DoS via excessive multipart form logging before 6.5.0.
}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2025},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2025-47287},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2025-47287/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.

The supreme art of war is to subdue the enemy without fighting.

Sun Tzu – “The Art of War”

:: Shaping the future through research and ingenuity ::