Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit a77ab24

Browse filesBrowse files
[3.8] gh-123067: Fix quadratic complexity in parsing "-quoted cookie values with backslashes (GH-123075) (#123108)
This fixes CVE-2024-7592. (cherry picked from commit 44e4583) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
1 parent b158a76 commit a77ab24
Copy full SHA for a77ab24

File tree

3 files changed

+47
-26
lines changed
Filter options

3 files changed

+47
-26
lines changed

‎Lib/http/cookies.py

Copy file name to clipboardExpand all lines: Lib/http/cookies.py
+8-26Lines changed: 8 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,13 @@ def _quote(str):
183183
return '"' + str.translate(_Translator) + '"'
184184

185185

186-
_OctalPatt = re.compile(r"\\[0-3][0-7][0-7]")
187-
_QuotePatt = re.compile(r"[\\].")
186+
_unquote_sub = re.compile(r'\\(?:([0-3][0-7][0-7])|(.))').sub
187+
188+
def _unquote_replace(m):
189+
if m[1]:
190+
return chr(int(m[1], 8))
191+
else:
192+
return m[2]
188193

189194
def _unquote(str):
190195
# If there aren't any doublequotes,
@@ -204,30 +209,7 @@ def _unquote(str):
204209
# \012 --> \n
205210
# \" --> "
206211
#
207-
i = 0
208-
n = len(str)
209-
res = []
210-
while 0 <= i < n:
211-
o_match = _OctalPatt.search(str, i)
212-
q_match = _QuotePatt.search(str, i)
213-
if not o_match and not q_match: # Neither matched
214-
res.append(str[i:])
215-
break
216-
# else:
217-
j = k = -1
218-
if o_match:
219-
j = o_match.start(0)
220-
if q_match:
221-
k = q_match.start(0)
222-
if q_match and (not o_match or k < j): # QuotePatt matched
223-
res.append(str[i:k])
224-
res.append(str[k+1])
225-
i = k + 2
226-
else: # OctalPatt matched
227-
res.append(str[i:j])
228-
res.append(chr(int(str[j+1:j+4], 8)))
229-
i = j + 4
230-
return _nulljoin(res)
212+
return _unquote_sub(_unquote_replace, str)
231213

232214
# The _getdate() routine is used to set the expiration time in the cookie's HTTP
233215
# header. By default, _getdate() returns the current time in the appropriate

‎Lib/test/test_http_cookies.py

Copy file name to clipboardExpand all lines: Lib/test/test_http_cookies.py
+38Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import unittest
66
from http import cookies
77
import pickle
8+
from test import support
89

910

1011
class CookieTests(unittest.TestCase):
@@ -58,6 +59,43 @@ def test_basic(self):
5859
for k, v in sorted(case['dict'].items()):
5960
self.assertEqual(C[k].value, v)
6061

62+
def test_unquote(self):
63+
cases = [
64+
(r'a="b=\""', 'b="'),
65+
(r'a="b=\\"', 'b=\\'),
66+
(r'a="b=\="', 'b=='),
67+
(r'a="b=\n"', 'b=n'),
68+
(r'a="b=\042"', 'b="'),
69+
(r'a="b=\134"', 'b=\\'),
70+
(r'a="b=\377"', 'b=\xff'),
71+
(r'a="b=\400"', 'b=400'),
72+
(r'a="b=\42"', 'b=42'),
73+
(r'a="b=\\042"', 'b=\\042'),
74+
(r'a="b=\\134"', 'b=\\134'),
75+
(r'a="b=\\\""', 'b=\\"'),
76+
(r'a="b=\\\042"', 'b=\\"'),
77+
(r'a="b=\134\""', 'b=\\"'),
78+
(r'a="b=\134\042"', 'b=\\"'),
79+
]
80+
for encoded, decoded in cases:
81+
with self.subTest(encoded):
82+
C = cookies.SimpleCookie()
83+
C.load(encoded)
84+
self.assertEqual(C['a'].value, decoded)
85+
86+
@support.requires_resource('cpu')
87+
def test_unquote_large(self):
88+
n = 10**6
89+
for encoded in r'\\', r'\134':
90+
with self.subTest(encoded):
91+
data = 'a="b=' + encoded*n + ';"'
92+
C = cookies.SimpleCookie()
93+
C.load(data)
94+
value = C['a'].value
95+
self.assertEqual(value[:3], 'b=\\')
96+
self.assertEqual(value[-2:], '\\;')
97+
self.assertEqual(len(value), n + 3)
98+
6199
def test_load(self):
62100
C = cookies.SimpleCookie()
63101
C.load('Customer="WILE_E_COYOTE"; Version=1; Path=/acme')
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix quadratic complexity in parsing ``"``-quoted cookie values with backslashes by :mod:`http.cookies`.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.