Skip to content

Commit 639e32a

Browse files
committed
pythongh-149144: Use decodeURIComponent() for UTF-8 support in js_output()
1 parent f1588d4 commit 639e32a

3 files changed

Lines changed: 21 additions & 16 deletions

File tree

Lib/http/cookies.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -391,18 +391,18 @@ def __repr__(self):
391391
return '<%s: %s>' % (self.__class__.__name__, self.OutputString())
392392

393393
def js_output(self, attrs=None):
394-
import base64
394+
import urllib.parse
395395
# Print javascript
396396
output_string = self.OutputString(attrs)
397397
if _has_control_character(output_string):
398398
raise CookieError("Control characters are not allowed in cookies")
399399
# Base64-encode value to avoid template
400400
# injection in cookie values.
401-
output_encoded = base64.b64encode(output_string.encode('utf-8')).decode("ascii")
401+
output_encoded = urllib.parse.quote(output_string, safe='', encoding='utf-8')
402402
return """
403403
<script type="text/javascript">
404404
<!-- begin hiding
405-
document.cookie = atob(\"%s\");
405+
document.cookie = decodeURIComponent(\"%s\");
406406
// end hiding -->
407407
</script>
408408
""" % (output_encoded,)

Lib/test/test_http_cookies.py

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
# Simple test suite for http/cookies.py
2-
import base64
32
import copy
43
import unittest
54
import doctest
65
from http import cookies
76
import pickle
87
from test import support
8+
import urllib.parse
99

1010

1111
class CookieTests(unittest.TestCase):
@@ -175,19 +175,20 @@ def test_load(self):
175175

176176
self.assertEqual(C.output(['path']),
177177
'Set-Cookie: Customer="WILE_E_COYOTE"; Path=/acme')
178-
cookie_encoded = base64.b64encode(b'Customer="WILE_E_COYOTE"; Path=/acme; Version=1').decode('ascii')
178+
cookie_encoded = urllib.parse.quote('Customer="WILE_E_COYOTE"; Path=/acme; Version=1', safe='', encoding='utf-8')
179+
self.assertNotIn('/', cookie_encoded)
179180
self.assertEqual(C.js_output(), fr"""
180181
<script type="text/javascript">
181182
<!-- begin hiding
182-
document.cookie = atob("{cookie_encoded}");
183+
document.cookie = decodeURIComponent("{cookie_encoded}");
183184
// end hiding -->
184185
</script>
185186
""")
186-
cookie_encoded = base64.b64encode(b'Customer="WILE_E_COYOTE"; Path=/acme').decode('ascii')
187+
cookie_encoded = urllib.parse.quote('Customer="WILE_E_COYOTE"; Path=/acme', safe='', encoding='utf-8')
187188
self.assertEqual(C.js_output(['path']), fr"""
188189
<script type="text/javascript">
189190
<!-- begin hiding
190-
document.cookie = atob("{cookie_encoded}");
191+
document.cookie = decodeURIComponent("{cookie_encoded}");
191192
// end hiding -->
192193
</script>
193194
""")
@@ -292,19 +293,19 @@ def test_quoted_meta(self):
292293

293294
self.assertEqual(C.output(['path']),
294295
'Set-Cookie: Customer="WILE_E_COYOTE"; Path=/acme')
295-
expected_encoded_cookie = base64.b64encode(b'Customer=\"WILE_E_COYOTE\"; Path=/acme; Version=1').decode('ascii')
296+
expected_encoded_cookie = urllib.parse.quote('Customer=\"WILE_E_COYOTE\"; Path=/acme; Version=1', safe='', encoding='utf-8')
296297
self.assertEqual(C.js_output(), fr"""
297298
<script type="text/javascript">
298299
<!-- begin hiding
299-
document.cookie = atob("{expected_encoded_cookie}");
300+
document.cookie = decodeURIComponent("{expected_encoded_cookie}");
300301
// end hiding -->
301302
</script>
302303
""")
303-
expected_encoded_cookie = base64.b64encode(b'Customer=\"WILE_E_COYOTE\"; Path=/acme').decode('ascii')
304+
expected_encoded_cookie = urllib.parse.quote('Customer=\"WILE_E_COYOTE\"; Path=/acme', safe='', encoding='utf-8')
304305
self.assertEqual(C.js_output(['path']), fr"""
305306
<script type="text/javascript">
306307
<!-- begin hiding
307-
document.cookie = atob("{expected_encoded_cookie}");
308+
document.cookie = decodeURIComponent("{expected_encoded_cookie}");
308309
// end hiding -->
309310
</script>
310311
""")
@@ -395,13 +396,14 @@ def test_setter(self):
395396
self.assertEqual(
396397
M.output(),
397398
"Set-Cookie: %s=%s; Path=/foo" % (i, "%s_coded_val" % i))
398-
expected_encoded_cookie = base64.b64encode(
399-
("%s=%s; Path=/foo" % (i, "%s_coded_val" % i)).encode("ascii")
400-
).decode('ascii')
399+
expected_encoded_cookie = urllib.parse.quote(
400+
"%s=%s; Path=/foo" % (i, "%s_coded_val" % i),
401+
safe='', encoding='utf-8',
402+
)
401403
expected_js_output = """
402404
<script type="text/javascript">
403405
<!-- begin hiding
404-
document.cookie = atob("%s");
406+
document.cookie = decodeURIComponent("%s");
405407
// end hiding -->
406408
</script>
407409
""" % (expected_encoded_cookie,)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fixes an issue introduced by CVE-2026-6019 patch. atob() in JavaScript
2+
processes bytes as 'latin-1', switches the encoding algorithm from base64 to
3+
percent encoding and uses the decodeURIComponent() JavaScript API.

0 commit comments

Comments
 (0)