summaryrefslogtreecommitdiffstats
path: root/meta-python/recipes-devtools/python/python3-tornado/CVE-2026-35536.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-python/recipes-devtools/python/python3-tornado/CVE-2026-35536.patch')
-rw-r--r--meta-python/recipes-devtools/python/python3-tornado/CVE-2026-35536.patch155
1 files changed, 155 insertions, 0 deletions
diff --git a/meta-python/recipes-devtools/python/python3-tornado/CVE-2026-35536.patch b/meta-python/recipes-devtools/python/python3-tornado/CVE-2026-35536.patch
new file mode 100644
index 0000000000..783d0aa116
--- /dev/null
+++ b/meta-python/recipes-devtools/python/python3-tornado/CVE-2026-35536.patch
@@ -0,0 +1,155 @@
1From 66587e51009457274cedec28f5fd43000d129e4e Mon Sep 17 00:00:00 2001
2From: Ben Darnell <ben@bendarnell.com>
3Date: Fri, 6 Mar 2026 14:50:25 -0500
4Subject: [PATCH] web: Validate characters in all cookie attributes.
5
6Our previous control character check was missing a check for
7U+007F, and also semicolons, which are only allowed in quoted
8parts of values. This commit checks all attributes and
9updates the set of disallowed characters.
10
11CVE: CVE-2026-35536
12Upstream-Status: Backport [https://github.com/tornadoweb/tornado/commit/24a2d96ea115f663b223887deb0060f13974c104]
13Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
14---
15 tornado/test/web_test.py | 65 ++++++++++++++++++++++++++++++++++++++++
16 tornado/web.py | 27 +++++++++++++++--
17 2 files changed, 89 insertions(+), 3 deletions(-)
18
19diff --git a/tornado/test/web_test.py b/tornado/test/web_test.py
20index 801a80ed..ae39e8fc 100644
21--- a/tornado/test/web_test.py
22+++ b/tornado/test/web_test.py
23@@ -1,3 +1,5 @@
24+import http
25+
26 from tornado.concurrent import Future
27 from tornado import gen
28 from tornado.escape import (
29@@ -291,11 +293,67 @@ class CookieTest(WebTestCase):
30 self.set_cookie("unicode_args", "blah", domain="foo.com", path="/foo")
31
32 class SetCookieSpecialCharHandler(RequestHandler):
33+ # "Special" characters are allowed in cookie values, but trigger special quoting.
34 def get(self):
35 self.set_cookie("equals", "a=b")
36 self.set_cookie("semicolon", "a;b")
37 self.set_cookie("quote", 'a"b')
38
39+ class SetCookieForbiddenCharHandler(RequestHandler):
40+ def get(self):
41+ # Control characters and semicolons raise errors in cookie names and attributes
42+ # (but not values, which are tested in SetCookieSpecialCharHandler)
43+ for char in list(map(chr, range(0x20))) + [chr(0x7F), ";"]:
44+ try:
45+ self.set_cookie("foo" + char, "bar")
46+ self.write(
47+ "Didn't get expected exception for char %r in name\n" % char
48+ )
49+ except http.cookies.CookieError as e:
50+ if "Invalid cookie attribute name" not in str(e):
51+ self.write(
52+ "unexpected exception for char %r in name: %s\n"
53+ % (char, e)
54+ )
55+
56+ try:
57+ self.set_cookie("foo", "bar", domain="example" + char + ".com")
58+ self.write(
59+ "Didn't get expected exception for char %r in domain\n"
60+ % char
61+ )
62+ except http.cookies.CookieError as e:
63+ if "Invalid cookie attribute domain" not in str(e):
64+ self.write(
65+ "unexpected exception for char %r in domain: %s\n"
66+ % (char, e)
67+ )
68+
69+ try:
70+ self.set_cookie("foo", "bar", path="/" + char)
71+ self.write(
72+ "Didn't get expected exception for char %r in path\n" % char
73+ )
74+ except http.cookies.CookieError as e:
75+ if "Invalid cookie attribute path" not in str(e):
76+ self.write(
77+ "unexpected exception for char %r in path: %s\n"
78+ % (char, e)
79+ )
80+
81+ try:
82+ self.set_cookie("foo", "bar", samesite="a" + char)
83+ self.write(
84+ "Didn't get expected exception for char %r in samesite\n"
85+ % char
86+ )
87+ except http.cookies.CookieError as e:
88+ if "Invalid cookie attribute samesite" not in str(e):
89+ self.write(
90+ "unexpected exception for char %r in samesite: %s\n"
91+ % (char, e)
92+ )
93+
94 class SetCookieOverwriteHandler(RequestHandler):
95 def get(self):
96 self.set_cookie("a", "b", domain="example.com")
97@@ -329,6 +387,7 @@ class CookieTest(WebTestCase):
98 ("/get", GetCookieHandler),
99 ("/set_domain", SetCookieDomainHandler),
100 ("/special_char", SetCookieSpecialCharHandler),
101+ ("/forbidden_char", SetCookieForbiddenCharHandler),
102 ("/set_overwrite", SetCookieOverwriteHandler),
103 ("/set_max_age", SetCookieMaxAgeHandler),
104 ("/set_expires_days", SetCookieExpiresDaysHandler),
105@@ -385,6 +444,12 @@ class CookieTest(WebTestCase):
106 response = self.fetch("/get", headers={"Cookie": header})
107 self.assertEqual(response.body, utf8(expected))
108
109+ def test_set_cookie_forbidden_char(self):
110+ response = self.fetch("/forbidden_char")
111+ self.assertEqual(response.code, 200)
112+ self.maxDiff = 10000
113+ self.assertMultiLineEqual(to_unicode(response.body), "")
114+
115 def test_set_cookie_overwrite(self):
116 response = self.fetch("/set_overwrite")
117 headers = response.headers.get_list("Set-Cookie")
118diff --git a/tornado/web.py b/tornado/web.py
119index 8a740504..4b70ea93 100644
120--- a/tornado/web.py
121+++ b/tornado/web.py
122@@ -643,9 +643,30 @@ class RequestHandler(object):
123 # The cookie library only accepts type str, in both python 2 and 3
124 name = escape.native_str(name)
125 value = escape.native_str(value)
126- if re.search(r"[\x00-\x20]", name + value):
127- # Don't let us accidentally inject bad stuff
128- raise ValueError("Invalid cookie %r: %r" % (name, value))
129+ if re.search(r"[\x00-\x20]", value):
130+ # Legacy check for control characters in cookie values. This check is no longer needed
131+ # since the cookie library escapes these characters correctly now. It will be removed
132+ # in the next feature release.
133+ raise ValueError(f"Invalid cookie {name!r}: {value!r}")
134+ for attr_name, attr_value in [
135+ ("name", name),
136+ ("domain", domain),
137+ ("path", path),
138+ ("samesite", samesite),
139+ ]:
140+ # Cookie attributes may not contain control characters or semicolons (except when
141+ # escaped in the value). A check for control characters was added to the http.cookies
142+ # library in a Feb 2026 security release; as of March it still does not check for
143+ # semicolons.
144+ #
145+ # When a semicolon check is added to the standard library (and the release has had time
146+ # for adoption), this check may be removed, but be mindful of the fact that this may
147+ # change the timing of the exception (to the generation of the Set-Cookie header in
148+ # flush()). We m
149+ if attr_value is not None and re.search(r"[\x00-\x20\x3b\x7f]", attr_value):
150+ raise http.cookies.CookieError(
151+ f"Invalid cookie attribute {attr_name}={attr_value!r} for cookie {name!r}"
152+ )
153 if not hasattr(self, "_new_cookie"):
154 self._new_cookie = (
155 http.cookies.SimpleCookie()