GHSA-wwv5-g3v4-889xLow▾ SunlitTornado: Incomplete fix for CVE-2026-35536: cookie attribute injection re-opened via the legacy case-insensitive `**kwargs` path in `set_cookie`
▾ Sunlit zone — Low / medium · no exploitation signal
impact 13.8 · likelihood 0 · exploitation 0
Need a working PoC? Pro members can cast a request and our team develops one — it lands right here.
Disclosure to exploitation, from the record and what we observed since indexing it.
Disclosed via OSV
Last analysed / modified upstream
The CVE-2026-35536 fix added a validation loop that rejects [\x00-\x20\x3b\x7f], but only for the
hardcoded lowercase keys name/domain/path/samesite. The still-live deprecated **kwargs path
writes attacker-supplied attribute values straight into the Morsel with no validation, and because
Morsel.__setitem__ is case-insensitive, a capitalized kwarg (Domain=, Path=, SameSite=, Max-Age=)
routes to the same reserved attribute while bypassing the loop — re-opening ;-delimited attribute injection.
self.set_cookie("sid", "abc", Domain="evil.com; Secure; SameSite=None")
# -> Set-Cookie: sid=abc; Domain=evil.com; Secure; SameSite=None; Path=/
# Sanity (the canonical lowercase named arg IS blocked):
self.set_cookie("sid", "abc", domain="evil.com; Secure") # -> http.cookies.CookieError
The patch's regression test (SetCookieForbiddenCharHandler) only exercises the four named params, never the
**kwargs path, so the gap is not regression-covered.
tornado/web.py → RequestHandler.set_cookie: the validation loop covers only the lowercase named args;
the trailing if kwargs: loop does morsel[k] = v with no character validation.GET /upper (uses Domain= kwarg) emits Set-Cookie: c_upper=v; Domain=evil.com; Secure; SameSite=None; Path=/; GET /lower (uses lowercase
domain=) returns a CookieError.
Injection of independent cookie attributes (force/drop Secure/HttpOnly/SameSite, rebind Domain/Path)
— the same impact CVE-2026-35536 closed, via the sibling path the patch missed. Conditional on the app using
a capitalized/legacy keyword.
Apply the same [\x00-\x20\x3b\x7f] validation to every entry in the **kwargs loop (after normalizing the
key case), or remove the deprecated kwargs path; add a regression test for capitalized kwargs.
Reported as part of an incomplete-patch measurement study (responsible disclosure).
tornado >= 6.5.5, < 6.5.8Upgrade to a patched release:
tornado 6.5.8Connected by shared product, vendor, weakness, or advisory.
CVE-2026-91990High· 7.5Tornado before 6.5.8 contains a memory amplification vulnerability in parse_multipart_form_data that splits multipart data before validating the max_parts limit
CVE-2026-91991Medium· 5.4Tornado before 6.5.8 contains an incomplete fix for cookie attribute injection that allows attackers to inject arbitrary cookie attributes by passing capitalized or legacy keyword arguments to set_cookie
CVE-2026-82397High· 7.5Tornado is a Python web framework and asynchronous networking library
GHSA-8423-8fgw-73vqMediumtornado: multipart split() creates huge temp list before max_parts check -> memory amplification DoS (httputil.py:34)
CVE-2024-58384Medium· 5.4Tornado before 6.4.1 contains a CRLF injection vulnerability in CurlAsyncHTTPClient that fails to reject carriage return and line feed characters in request headers
CVE-2023-54397High· 7.5Tornado before 6.3.3 contains an HTTP request smuggling vulnerability due to improper parsing of Content-Length headers accepting non-standard characters