low

GHSA-wwv5-g3v4-889x

PyPI · tornado

Summary

Tornado: Incomplete fix for CVE-2026-35536: cookie attribute injection re-opened via the legacy case-insensitive `**kwargs` path in `set_cookie`

Severity
low
CWE
CWE-74
Published
2026-09-01
Updated
2026-09-01

Advisory details

Summary

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.

Affected code

Steps to reproduce

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.

Impact

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.

Suggested remediation

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.

Credit

Reported as part of an incomplete-patch measurement study (responsible disclosure).

References

Related advisories

Is your project exposed to this? Stateward checks every dependency on every pull request and flags it only if your code actually reaches it.

Check my repo

Summarize with AI

ChatGPTClaudePerplexity

Sources: CISA KEV (public domain), OSV.dev & GitHub Advisory Database (CC-BY-4.0), FIRST EPSS, NVD/CWE (public domain). Served live from the Stateward advisory database.