FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

[CVE-2026-1502] Reject CR/LF in HTTP tunnel request headers · openSUSE-Python/cpython@4d1cf9f · GitHub

Repository navigation

Commit 4d1cf9f

Browse files
authored andcommitted
[CVE-2026-1502] Reject CR/LF in HTTP tunnel request headers
This patch fixes a CRLF injection vulnerability in http.client by enforcing that carriage return and line feed characters are rejected in proxy tunnel headers and host fields to prevent HTTP response splitting and header injection. Fixes: bsc#1261969 (CVE-2026-1502) Fixes: gh#python#146211 From-PR: gh#python/cpython!146212 Patch: CVE-2026-1502-reject-CRLF-HTTP-tunnel.patch
1 parent 228a60c commit 4d1cf9f

3 files changed

Lines changed: 65 additions & 3 deletions

File tree

‎Lib/http/client.py‎

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -936,14 +936,29 @@ def set_debuglevel(self, level):
936936
self.debuglevel = level
937937

938938
def _tunnel(self):
939+
if _contains_disallowed_url_pchar_re.search(self._tunnel_host):
940+
raise ValueError('Tunnel host can\'t contain control characters %r'
941+
% (self._tunnel_host,))
939942
connect_str = "CONNECT %s:%d HTTP/1.0\r\n" % (self._tunnel_host,
940943
self._tunnel_port)
941944
connect_bytes = connect_str.encode("ascii")
942945
self.send(connect_bytes)
943946
for header, value in self._tunnel_headers.items():
944-
header_str = "%s: %s\r\n" % (header, value)
945-
header_bytes = header_str.encode("latin-1")
946-
self.send(header_bytes)
947+
if hasattr(header, 'encode'):
948+
header = header.encode('ascii')
949+
950+
if not _is_legal_header_name(header):
951+
raise ValueError('Invalid header name %r' % (header,))
952+
953+
if hasattr(value, 'encode'):
954+
value = value.encode('latin-1')
955+
elif isinstance(value, int):
956+
value = str(value).encode('ascii')
957+
958+
if _is_illegal_header_value(value):
959+
raise ValueError('Invalid header value %r' % (value,))
960+
961+
self.send(header + b': ' + value + b'\r\n')
947962
self.send(b'\r\n')
948963

949964
response = self.response_class(self.sock, method=self._method)

‎Lib/test/test_httplib.py‎

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,51 @@ def test_invalid_headers(self):
344344
with self.assertRaisesRegex(ValueError, 'Invalid header'):
345345
conn.putheader(name, value)
346346

347+
def test_invalid_tunnel_headers(self):
348+
cases = (
349+
('Invalid\r\nName', 'ValidValue'),
350+
('Invalid\rName', 'ValidValue'),
351+
('Invalid\nName', 'ValidValue'),
352+
('\r\nInvalidName', 'ValidValue'),
353+
('\rInvalidName', 'ValidValue'),
354+
('\nInvalidName', 'ValidValue'),
355+
(' InvalidName', 'ValidValue'),
356+
('\tInvalidName', 'ValidValue'),
357+
('Invalid:Name', 'ValidValue'),
358+
(':InvalidName', 'ValidValue'),
359+
('ValidName', 'Invalid\r\nValue'),
360+
('ValidName', 'Invalid\rValue'),
361+
('ValidName', 'Invalid\nValue'),
362+
('ValidName', 'InvalidValue\r\n'),
363+
('ValidName', 'InvalidValue\r'),
364+
('ValidName', 'InvalidValue\n'),
365+
)
366+
for name, value in cases:
367+
with self.subTest((name, value)):
368+
conn = client.HTTPConnection('example.com')
369+
conn.set_tunnel('tunnel', headers={
370+
name: value
371+
})
372+
conn.sock = FakeSocket('')
373+
with self.assertRaisesRegex(ValueError, 'Invalid header'):
374+
conn._tunnel() # Called in .connect()
375+
376+
def test_invalid_tunnel_host(self):
377+
cases = (
378+
'invalid\r.host',
379+
'\ninvalid.host',
380+
'invalid.host\r\n',
381+
'invalid.host\x00',
382+
'invalid host',
383+
)
384+
for tunnel_host in cases:
385+
with self.subTest(tunnel_host):
386+
conn = client.HTTPConnection('example.com')
387+
conn.set_tunnel(tunnel_host)
388+
conn.sock = FakeSocket('')
389+
with self.assertRaisesRegex(ValueError, 'Tunnel host can\'t contain control characters'):
390+
conn._tunnel() # Called in .connect()
391+
347392
def test_headers_debuglevel(self):
348393
body = (
349394
b'HTTP/1.1 200 OK\r\n'
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Reject CR/LF characters in tunnel request headers for the
2+
HTTPConnection.set_tunnel() method.

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL