[3.14] gh-90309: Base64-encode cookie values embedded in JS (GH-148889)

(cherry picked from commit 76b3923d68)

Co-authored-by: Seth Larson <seth@python.org>
This commit is contained in:
Miss Islington (bot)
2026-04-23 15:05:09 +02:00
committed by GitHub
parent dd9a77ff2e
commit f795e04204
3 changed files with 27 additions and 13 deletions
+6 -2
View File
@@ -391,17 +391,21 @@ class Morsel(dict):
return '<%s: %s>' % (self.__class__.__name__, self.OutputString())
def js_output(self, attrs=None):
import base64
# Print javascript
output_string = self.OutputString(attrs)
if _has_control_character(output_string):
raise CookieError("Control characters are not allowed in cookies")
# Base64-encode value to avoid template
# injection in cookie values.
output_encoded = base64.b64encode(output_string.encode('utf-8')).decode("ascii")
return """
<script type="text/javascript">
<!-- begin hiding
document.cookie = \"%s\";
document.cookie = atob(\"%s\");
// end hiding -->
</script>
""" % (output_string.replace('"', r'\"'))
""" % (output_encoded,)
def OutputString(self, attrs=None):
# Build up our result
+18 -11
View File
@@ -1,5 +1,5 @@
# Simple test suite for http/cookies.py
import base64
import copy
import unittest
import doctest
@@ -152,17 +152,19 @@ class CookieTests(unittest.TestCase):
self.assertEqual(C.output(['path']),
'Set-Cookie: Customer="WILE_E_COYOTE"; Path=/acme')
self.assertEqual(C.js_output(), r"""
cookie_encoded = base64.b64encode(b'Customer="WILE_E_COYOTE"; Path=/acme; Version=1').decode('ascii')
self.assertEqual(C.js_output(), fr"""
<script type="text/javascript">
<!-- begin hiding
document.cookie = "Customer=\"WILE_E_COYOTE\"; Path=/acme; Version=1";
document.cookie = atob("{cookie_encoded}");
// end hiding -->
</script>
""")
self.assertEqual(C.js_output(['path']), r"""
cookie_encoded = base64.b64encode(b'Customer="WILE_E_COYOTE"; Path=/acme').decode('ascii')
self.assertEqual(C.js_output(['path']), fr"""
<script type="text/javascript">
<!-- begin hiding
document.cookie = "Customer=\"WILE_E_COYOTE\"; Path=/acme";
document.cookie = atob("{cookie_encoded}");
// end hiding -->
</script>
""")
@@ -267,17 +269,19 @@ class CookieTests(unittest.TestCase):
self.assertEqual(C.output(['path']),
'Set-Cookie: Customer="WILE_E_COYOTE"; Path=/acme')
self.assertEqual(C.js_output(), r"""
expected_encoded_cookie = base64.b64encode(b'Customer=\"WILE_E_COYOTE\"; Path=/acme; Version=1').decode('ascii')
self.assertEqual(C.js_output(), fr"""
<script type="text/javascript">
<!-- begin hiding
document.cookie = "Customer=\"WILE_E_COYOTE\"; Path=/acme; Version=1";
document.cookie = atob("{expected_encoded_cookie}");
// end hiding -->
</script>
""")
self.assertEqual(C.js_output(['path']), r"""
expected_encoded_cookie = base64.b64encode(b'Customer=\"WILE_E_COYOTE\"; Path=/acme').decode('ascii')
self.assertEqual(C.js_output(['path']), fr"""
<script type="text/javascript">
<!-- begin hiding
document.cookie = "Customer=\"WILE_E_COYOTE\"; Path=/acme";
document.cookie = atob("{expected_encoded_cookie}");
// end hiding -->
</script>
""")
@@ -368,13 +372,16 @@ class MorselTests(unittest.TestCase):
self.assertEqual(
M.output(),
"Set-Cookie: %s=%s; Path=/foo" % (i, "%s_coded_val" % i))
expected_encoded_cookie = base64.b64encode(
("%s=%s; Path=/foo" % (i, "%s_coded_val" % i)).encode("ascii")
).decode('ascii')
expected_js_output = """
<script type="text/javascript">
<!-- begin hiding
document.cookie = "%s=%s; Path=/foo";
document.cookie = atob("%s");
// end hiding -->
</script>
""" % (i, "%s_coded_val" % i)
""" % (expected_encoded_cookie,)
self.assertEqual(M.js_output(), expected_js_output)
for i in ["foo bar", "foo@bar"]:
# Try some illegal characters
@@ -0,0 +1,3 @@
Base64-encode values when embedding cookies to JavaScript using the
:meth:`http.cookies.BaseCookie.js_output` method to avoid injection
and escaping.