Skip to content

Commit f02de96

Browse 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

File tree

3 files changed

+39
-0
lines changed

3 files changed

+39
-0
lines changed

Lib/http/client.py

Lines 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

Lines 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

Lines 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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy