HTTPServerRequest.__init__ in tornado/httputil.py parses the URL query string via
parse_qs_bytes() with no field-count limit — while the sibling POST-body parsing path
(parse_body_arguments) received a max_num_fields=1000 cap added earlier in this exact
same release (v6.5.8, commit 8d6363ed), explicitly to bound parsing cost for the identical
underlying primitive. This leaves the query-string path with the resource-exhaustion exposure
the body-path fix was meant to close.
File: tornado/httputil.py, line 553 (HTTPServerRequest.__init__)
# tornado/httputil.py:553 (before fix)
self.arguments = parse_qs_bytes(self.query, keep_blank_values=True)
Compare with the POST-body path fixed one commit earlier in the same release:
# tornado/httputil.py:1038-1041
uri_arguments = parse_qs_bytes(
body,
keep_blank_values=True,
max_num_fields=config.urlencoded.max_arguments, # default 1000
)
Both call sites funnel through the same tornado.escape.parse_qs_bytes (a thin wrapper over
urllib.parse.parse_qs), which is exactly why max_num_fields was added to
urllib.parse.parse_qsl upstream — to let frameworks bound field count. The fix was applied
only to the body path; the query-string path was missed.
The request line + headers together are capped at max_header_size (default 65536 bytes), so
this is not literally unbounded, but a single ~64KB request line can carry thousands of short
key=value pairs — far beyond the 1000-field limit the maintainer judged appropriate for the
structurally identical body case.
GET request whose query string is packed with thousands of short fields
(e.g. k0=1&k1=1&...&k7799=1, ~61KB), fitting comfortably under max_header_size. No
authentication, cookies, or prior state required.IOLoop. Several such requests in flight concurrently stall the event
loop, delaying processing of all other connections on that loop — not just the
attacker's own request.Ran the unmodified v6.5.8 source directly (no external dependencies needed) with a minimal
tornado.web.Application on 127.0.0.1:8888.
200 OK; sent as POST body
(application/x-www-form-urlencoded) → 400 Bad Request (correctly rejected by the
existing max_num_fields body-path limit). This confirms the asymmetry directly./?a=1) averaged 1.86ms; the 7800-field query string
averaged 25.1ms (~13x).All Tornado servers/applications are affected — this triggers on every request with a query
string, independent of application/handler logic. An unauthenticated, unprivileged remote
attacker can measurably degrade response times for all other clients sharing the same
IOLoop, using a small amount of bandwidth and no special conditions. This is an
availability/DoS concern; no confidentiality or integrity impact.
# tornado/httputil.py — HTTPServerRequest.__init__
if uri is not None:
self.path, sep, self.query = uri.partition("?")
try:
self.arguments = parse_qs_bytes(
self.query,
keep_blank_values=True,
max_num_fields=_DEFAULT_PARSE_BODY_CONFIG.urlencoded.max_arguments,
)
except ValueError as e:
raise HTTPInputError("Invalid query string: %s" % e) from e
This reuses the existing ParseUrlEncodedConfig.max_arguments default (1000) via the
module's _DEFAULT_PARSE_BODY_CONFIG, matching the POST-body limit and honoring any global
override via set_parse_body_config(). The try/except is necessary because — unlike
parse_body_arguments, which already wraps its call and converts ValueError into a clean
HTTPInputError/400 — the query-string call site currently has no such handling, so without
it, a request exceeding the limit would raise an uncaught ValueError instead of a clean 400.
Verified: with the fix applied, requests with ≤1000 query-string fields are unaffected;
requests with >1000 fields are rejected with 400 Bad Request (consistent with the POST-body
behavior); Tornado's own httputil_test and web_test suites (256 tests) pass unchanged.
| Software | Affected versions |
|---|---|
tornado
|
< 6.5.9 |
A vulnerability database tells you what is broken. Attack surface management tells you where it is running: it discovers your internet-facing assets and flags the ones affected by issues like this one.
What is attack surface management? →A security vulnerability is a weakness in software, hardware, or configuration that can be exploited to compromise confidentiality, integrity, or availability. Many vulnerabilities are tracked as CVEs (Common Vulnerabilities and Exposures), which provide a standardized identifier so teams can coordinate patching, mitigation, and risk assessment across tools and vendors.
CVSS (Common Vulnerability Scoring System) estimates technical severity, but it doesn't automatically equal business risk. Prioritize using context like internet exposure, affected asset criticality, known exploitation (proof-of-concept or in-the-wild), and whether compensating controls exist. A "Medium" CVSS on an exposed, production system can be more urgent than a "Critical" on an isolated, non-production host.
A vulnerability is the underlying weakness. An exploit is the method or code used to take advantage of it. A zero-day is a vulnerability that is unknown to the vendor or has no publicly available fix when attackers begin using it. In practice, risk increases sharply when exploitation becomes reliable or widespread.
Recurring findings usually come from incomplete Asset Discovery, inconsistent patch management, inherited images, and configuration drift. In modern environments, you also need to watch the software supply chain: dependencies, containers, build pipelines, and third-party services can reintroduce the same weakness even after you patch a single host. Unknown or unmanaged assets (often called Shadow IT) are a common reason the same issues resurface.
Use a simple, repeatable triage model: focus first on externally exposed assets, high-value systems (identity, VPN, email, production), vulnerabilities with known exploits, and issues that enable remote code execution or privilege escalation. Then enforce patch SLAs and track progress using consistent metrics so remediation is steady, not reactive.
SynScan combines attack surface monitoring and continuous security auditing to keep your inventory current, flag high-impact vulnerabilities early, and help you turn raw findings into a practical remediation plan.