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 f02de96

Browse filesBrowse files
bpo-39603: Prevent header injection in http methods (GH-18485) (GH-21539)
reject control chars in http method in http.client.putrequest to prevent http header injection (cherry picked from commit 8ca8a2e) Co-authored-by: AMIR <31338382+amiremohamadi@users.noreply.github.com>
1 parent 47a2955 commit f02de96
Copy full SHA for f02de96

File tree

Expand file treeCollapse file tree

3 files changed

+39
-0
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+39
-0
lines changed

‎Lib/http/client.py

Copy file name to clipboardExpand all lines: Lib/http/client.py
+15Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,10 @@
151151
# _is_allowed_url_pchars_re = re.compile(r"^[/!$&'()*+,;=:@%a-zA-Z0-9._~-]+$")
152152
# We are more lenient for assumed real world compatibility purposes.
153153

154+
# These characters are not allowed within HTTP method names
155+
# to prevent http header injection.
156+
_contains_disallowed_method_pchar_re = re.compile('[\x00-\x1f]')
157+
154158
# We always set the Content-Length header for these methods because some
155159
# servers will otherwise respond with a 411
156160
_METHODS_EXPECTING_BODY = {'PATCH', 'POST', 'PUT'}
@@ -1119,6 +1123,8 @@ def putrequest(self, method, url, skip_host=False,
11191123
else:
11201124
raise CannotSendRequest(self.__state)
11211125

1126+
self._validate_method(method)
1127+
11221128
# Save the method for use later in the response phase
11231129
self._method = method
11241130

@@ -1209,6 +1215,15 @@ def _encode_request(self, request):
12091215
# ASCII also helps prevent CVE-2019-9740.
12101216
return request.encode('ascii')
12111217

1218+
def _validate_method(self, method):
1219+
"""Validate a method name for putrequest."""
1220+
# prevent http header injection
1221+
match = _contains_disallowed_method_pchar_re.search(method)
1222+
if match:
1223+
raise ValueError(
1224+
f"method can't contain control characters. {method!r} "
1225+
f"(found at least {match.group()!r})")
1226+
12121227
def _validate_path(self, url):
12131228
"""Validate a url for putrequest."""
12141229
# Prevent CVE-2019-9740.

‎Lib/test/test_httplib.py

Copy file name to clipboardExpand all lines: Lib/test/test_httplib.py
+22Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,28 @@ def test_headers_debuglevel(self):
359359
self.assertEqual(lines[2], "header: Second: val")
360360

361361

362+
class HttpMethodTests(TestCase):
363+
def test_invalid_method_names(self):
364+
methods = (
365+
'GET\r',
366+
'POST\n',
367+
'PUT\n\r',
368+
'POST\nValue',
369+
'POST\nHOST:abc',
370+
'GET\nrHost:abc\n',
371+
'POST\rRemainder:\r',
372+
'GET\rHOST:\n',
373+
'\nPUT'
374+
)
375+
376+
for method in methods:
377+
with self.assertRaisesRegex(
378+
ValueError, "method can't contain control characters"):
379+
conn = client.HTTPConnection('example.com')
380+
conn.sock = FakeSocket(None)
381+
conn.request(method=method, url="/")
382+
383+
362384
class TransferEncodingTest(TestCase):
363385
expected_body = b"It's just a flesh wound"
364386

+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Prevent http header injection by rejecting control characters in
2+
http.client.putrequest(...).

0 commit comments

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