mirror of
git://git.openembedded.org/meta-openembedded
synced 2026-04-18 23:36:24 +00:00
Backport the commit[1] from version 6.5.5 which fixes this vulnerability
according to the NVD[2].
[1] 24a2d96ea1
[2] https://nvd.nist.gov/vuln/detail/CVE-2026-35536
Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
Signed-off-by: Anuj Mittal <anuj.mittal@oss.qualcomm.com>
156 lines
7.4 KiB
Diff
156 lines
7.4 KiB
Diff
From 66587e51009457274cedec28f5fd43000d129e4e Mon Sep 17 00:00:00 2001
|
|
From: Ben Darnell <ben@bendarnell.com>
|
|
Date: Fri, 6 Mar 2026 14:50:25 -0500
|
|
Subject: [PATCH] web: Validate characters in all cookie attributes.
|
|
|
|
Our previous control character check was missing a check for
|
|
U+007F, and also semicolons, which are only allowed in quoted
|
|
parts of values. This commit checks all attributes and
|
|
updates the set of disallowed characters.
|
|
|
|
CVE: CVE-2026-35536
|
|
Upstream-Status: Backport [https://github.com/tornadoweb/tornado/commit/24a2d96ea115f663b223887deb0060f13974c104]
|
|
Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
|
|
---
|
|
tornado/test/web_test.py | 65 ++++++++++++++++++++++++++++++++++++++++
|
|
tornado/web.py | 27 +++++++++++++++--
|
|
2 files changed, 89 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/tornado/test/web_test.py b/tornado/test/web_test.py
|
|
index 801a80ed..ae39e8fc 100644
|
|
--- a/tornado/test/web_test.py
|
|
+++ b/tornado/test/web_test.py
|
|
@@ -1,3 +1,5 @@
|
|
+import http
|
|
+
|
|
from tornado.concurrent import Future
|
|
from tornado import gen
|
|
from tornado.escape import (
|
|
@@ -291,11 +293,67 @@ class CookieTest(WebTestCase):
|
|
self.set_cookie("unicode_args", "blah", domain="foo.com", path="/foo")
|
|
|
|
class SetCookieSpecialCharHandler(RequestHandler):
|
|
+ # "Special" characters are allowed in cookie values, but trigger special quoting.
|
|
def get(self):
|
|
self.set_cookie("equals", "a=b")
|
|
self.set_cookie("semicolon", "a;b")
|
|
self.set_cookie("quote", 'a"b')
|
|
|
|
+ class SetCookieForbiddenCharHandler(RequestHandler):
|
|
+ def get(self):
|
|
+ # Control characters and semicolons raise errors in cookie names and attributes
|
|
+ # (but not values, which are tested in SetCookieSpecialCharHandler)
|
|
+ for char in list(map(chr, range(0x20))) + [chr(0x7F), ";"]:
|
|
+ try:
|
|
+ self.set_cookie("foo" + char, "bar")
|
|
+ self.write(
|
|
+ "Didn't get expected exception for char %r in name\n" % char
|
|
+ )
|
|
+ except http.cookies.CookieError as e:
|
|
+ if "Invalid cookie attribute name" not in str(e):
|
|
+ self.write(
|
|
+ "unexpected exception for char %r in name: %s\n"
|
|
+ % (char, e)
|
|
+ )
|
|
+
|
|
+ try:
|
|
+ self.set_cookie("foo", "bar", domain="example" + char + ".com")
|
|
+ self.write(
|
|
+ "Didn't get expected exception for char %r in domain\n"
|
|
+ % char
|
|
+ )
|
|
+ except http.cookies.CookieError as e:
|
|
+ if "Invalid cookie attribute domain" not in str(e):
|
|
+ self.write(
|
|
+ "unexpected exception for char %r in domain: %s\n"
|
|
+ % (char, e)
|
|
+ )
|
|
+
|
|
+ try:
|
|
+ self.set_cookie("foo", "bar", path="/" + char)
|
|
+ self.write(
|
|
+ "Didn't get expected exception for char %r in path\n" % char
|
|
+ )
|
|
+ except http.cookies.CookieError as e:
|
|
+ if "Invalid cookie attribute path" not in str(e):
|
|
+ self.write(
|
|
+ "unexpected exception for char %r in path: %s\n"
|
|
+ % (char, e)
|
|
+ )
|
|
+
|
|
+ try:
|
|
+ self.set_cookie("foo", "bar", samesite="a" + char)
|
|
+ self.write(
|
|
+ "Didn't get expected exception for char %r in samesite\n"
|
|
+ % char
|
|
+ )
|
|
+ except http.cookies.CookieError as e:
|
|
+ if "Invalid cookie attribute samesite" not in str(e):
|
|
+ self.write(
|
|
+ "unexpected exception for char %r in samesite: %s\n"
|
|
+ % (char, e)
|
|
+ )
|
|
+
|
|
class SetCookieOverwriteHandler(RequestHandler):
|
|
def get(self):
|
|
self.set_cookie("a", "b", domain="example.com")
|
|
@@ -329,6 +387,7 @@ class CookieTest(WebTestCase):
|
|
("/get", GetCookieHandler),
|
|
("/set_domain", SetCookieDomainHandler),
|
|
("/special_char", SetCookieSpecialCharHandler),
|
|
+ ("/forbidden_char", SetCookieForbiddenCharHandler),
|
|
("/set_overwrite", SetCookieOverwriteHandler),
|
|
("/set_max_age", SetCookieMaxAgeHandler),
|
|
("/set_expires_days", SetCookieExpiresDaysHandler),
|
|
@@ -385,6 +444,12 @@ class CookieTest(WebTestCase):
|
|
response = self.fetch("/get", headers={"Cookie": header})
|
|
self.assertEqual(response.body, utf8(expected))
|
|
|
|
+ def test_set_cookie_forbidden_char(self):
|
|
+ response = self.fetch("/forbidden_char")
|
|
+ self.assertEqual(response.code, 200)
|
|
+ self.maxDiff = 10000
|
|
+ self.assertMultiLineEqual(to_unicode(response.body), "")
|
|
+
|
|
def test_set_cookie_overwrite(self):
|
|
response = self.fetch("/set_overwrite")
|
|
headers = response.headers.get_list("Set-Cookie")
|
|
diff --git a/tornado/web.py b/tornado/web.py
|
|
index 8a740504..4b70ea93 100644
|
|
--- a/tornado/web.py
|
|
+++ b/tornado/web.py
|
|
@@ -643,9 +643,30 @@ class RequestHandler(object):
|
|
# The cookie library only accepts type str, in both python 2 and 3
|
|
name = escape.native_str(name)
|
|
value = escape.native_str(value)
|
|
- if re.search(r"[\x00-\x20]", name + value):
|
|
- # Don't let us accidentally inject bad stuff
|
|
- raise ValueError("Invalid cookie %r: %r" % (name, value))
|
|
+ if re.search(r"[\x00-\x20]", value):
|
|
+ # Legacy check for control characters in cookie values. This check is no longer needed
|
|
+ # since the cookie library escapes these characters correctly now. It will be removed
|
|
+ # in the next feature release.
|
|
+ raise ValueError(f"Invalid cookie {name!r}: {value!r}")
|
|
+ for attr_name, attr_value in [
|
|
+ ("name", name),
|
|
+ ("domain", domain),
|
|
+ ("path", path),
|
|
+ ("samesite", samesite),
|
|
+ ]:
|
|
+ # Cookie attributes may not contain control characters or semicolons (except when
|
|
+ # escaped in the value). A check for control characters was added to the http.cookies
|
|
+ # library in a Feb 2026 security release; as of March it still does not check for
|
|
+ # semicolons.
|
|
+ #
|
|
+ # When a semicolon check is added to the standard library (and the release has had time
|
|
+ # for adoption), this check may be removed, but be mindful of the fact that this may
|
|
+ # change the timing of the exception (to the generation of the Set-Cookie header in
|
|
+ # flush()). We m
|
|
+ if attr_value is not None and re.search(r"[\x00-\x20\x3b\x7f]", attr_value):
|
|
+ raise http.cookies.CookieError(
|
|
+ f"Invalid cookie attribute {attr_name}={attr_value!r} for cookie {name!r}"
|
|
+ )
|
|
if not hasattr(self, "_new_cookie"):
|
|
self._new_cookie = (
|
|
http.cookies.SimpleCookie()
|