DEV Community

CVE Reports
CVE Reports

Posted on Originally published at cvereports.com

CVE-2026-116577: CVE-2026-116577: Algorithmic Complexity Denial of Service in Tornado HTTP Header Parser

CVE-2026-116577: Algorithmic Complexity Denial of Service in Tornado HTTP Header Parser

Vulnerability ID: CVE-2026-116577
CVSS Score: 5.3
Published: 2026-10-28

Tornado versions prior to 6.6.0 contain an inefficient algorithmic complexity vulnerability in the HTTP header parser. When processing requests with obsolete line folding (obs-fold), the HTTPHeaders.parse_line method repeatedly concatenates immutable Python strings within a list structure. An unauthenticated remote attacker can send an HTTP request containing thousands of short header continuation lines to trigger quadratic O(N^2) CPU consumption on the main IOLoop thread, starving concurrent connections and resulting in a denial of service.

TL;DR

An algorithmic complexity flaw in Tornado's HTTP header parser (< 6.6.0) allows unauthenticated attackers to cause quadratic CPU consumption and block the asynchronous event loop by sending requests with thousands of obsolete folded header lines.


Technical Details

  • Vulnerability Type: Inefficient Algorithmic Complexity (CWE-407)
  • Affected Component: tornado.httputil.HTTPHeaders.parse_line
  • Attack Vector: Network (Unauthenticated HTTP/1.x Request)
  • 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)
  • EPSS Score: 0.38% (32.33rd Percentile)
  • Security Impact: IOLoop Thread Starvation / Denial of Service
  • Exploit Status: No Known Public Weaponized Exploits
  • Patched Version: Tornado 6.6.0

Affected Systems

  • Tornado (PyPI package: tornado)
  • Tornado: < 6.6.0 (Fixed in: 6.6.0)

Code Analysis

Commit: 1b7a1dc

httputil: Remove support for header line folding due to DoS concerns

@@ -184,7 +184,6 @@ def __init__(self, *args: typing.Any, **kwargs: str) -> None:
         # on demand (and cleared whenever the list is modified).
         self._as_list: dict[str, list[str]] = {}
         self._combined_cache: dict[str, str] = {}
-        self._last_key: str | None = None
         if len(args) == 1 and len(kwargs) == 0 and isinstance(args[0], HTTPHeaders):
             # Copy constructor
             for k, v in args[0].get_all():
@@ -208,7 +207,6 @@ def add(self, name: str, value: str, *, _chars_are_bytes: bool = True) -> None:
             if _FORBIDDEN_HEADER_CHARS_RE.search(value):
                 raise HTTPInputError("Invalid header value %r" % value)
         norm_name = _normalize_header(name)
-        self._last_key = norm_name
         if norm_name in self:
             self._combined_cache.pop(norm_name, None)
             self._as_list[norm_name].append(value)
@@ -249,6 +247,11 @@ def parse_line(self, line: str, *, _chars_are_bytes: bool = True) -> None:
            In Tornado 7.0, certain deprecated features of HTTP will become errors.
            Specifically, line folding and the use of LF (with CR) as a line separator
            will be removed.
+
+        .. versionchanged:: 6.6
+           Support for line folding was removed due to security/DoS concerns. This removal
+           was ahead of the original removal schedule announced for Tornado 7.0.
+           Support for LF without CR remains until Tornado 7.0.
         """
         if m := re.search(r"\r?\n$", line):
             # RFC 9112 section 2.2: a recipient MAY recognize a single LF as a line
@@ -259,27 +262,14 @@ def parse_line(self, line: str, *, _chars_are_bytes: bool = True) -> None:
             # Empty line, or the final CRLF of a header block.
             return
         if line[0] in HTTP_WHITESPACE:
-            # continuation of a multi-line header
-            # TODO(7.0): Remove support for line folding.
-            if self._last_key is None:
-                raise HTTPInputError("first header line cannot start with whitespace")
-            new_part = " " + line.strip(HTTP_WHITESPACE)
-            if _chars_are_bytes:
-                if not _ABNF.field_value.fullmatch(new_part[1:]):
-                    raise HTTPInputError("Invalid header continuation %r" % new_part)
-            else:
-                if _FORBIDDEN_HEADER_CHARS_RE.search(new_part):
-                    raise HTTPInputError("Invalid header value %r" % new_part)
-            self._as_list[self._last_key][-1] += new_part
-            self._combined_cache.pop(self._last_key, None)
-        else:
-            try:
-                name, value = line.split(":", 1)
-            except ValueError:
-                raise HTTPInputError("no colon in header line")
-            self.add(
-                name, value.strip(HTTP_WHITESPACE), _chars_are_bytes=_chars_are_bytes
+            raise HTTPInputError(
+                "header line cannot start with whitespace, folding not supported"
             )
+        try:
+            name, value = line.split(":", 1)
+        except ValueError:
+            raise HTTPInputError("no colon in header line")
+        self.add(name, value.strip(HTTP_WHITESPACE), _chars_are_bytes=_chars_are_bytes)
Enter fullscreen mode Exit fullscreen mode

Mitigation Strategies

  • Upgrade Tornado to version 6.6.0 or newer to reject obsolete line folding at the parser level.
  • Deploy an RFC 9112-compliant reverse proxy (e.g., Nginx, Envoy, HAProxy) in front of Tornado to reject or unfold multi-line HTTP headers before they reach the Python process.
  • Reduce the max_header_size parameter on Tornado HTTPServer instances from the default 64 KB to a smaller value (such as 8 KB) to limit the quadratic amplification bound.
  • Run multiple Tornado worker processes behind a load balancer to isolate event loop starvation to individual worker processes.

Remediation Steps:

  1. Audit project dependencies (requirements.txt, pyproject.toml, Pipfile, or poetry.lock) to identify Tornado versions earlier than 6.6.0.
  2. Update the tornado package dependency to >= 6.6.0 using pip (pip install --upgrade 'tornado>=6.6.0') or your preferred package manager.
  3. Verify that no internal clients or upstream HTTP servers send obsolete multi-line folded headers, as Tornado 6.6.0 will reject them with HTTP 400.
  4. Redeploy the application services and verify the running Tornado version.

References


Read the full report for CVE-2026-116577 on our website for more details including interactive diagrams and full exploit analysis.

Top comments (0)