Skip to content

Commit f8b4bcc

Browse files
coletdjnzpukkandan
authored andcommitted
[core] Prevent Cookie leaks on HTTP redirect
Ref: GHSA-v8mc-9377-rwjj Authored by: coletdjnz
1 parent 1ceb657 commit f8b4bcc

File tree

2 files changed

+38
-2
lines changed

2 files changed

+38
-2
lines changed

Diff for: test/test_http.py

+31
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,11 @@ def do_GET(self):
132132
self._method('GET')
133133
elif self.path.startswith('/headers'):
134134
self._headers()
135+
elif self.path.startswith('/308-to-headers'):
136+
self.send_response(308)
137+
self.send_header('Location', '/headers')
138+
self.send_header('Content-Length', '0')
139+
self.end_headers()
135140
elif self.path == '/trailing_garbage':
136141
payload = b'<html><video src="/vid.mp4" /></html>'
137142
self.send_response(200)
@@ -270,6 +275,7 @@ def do_req(redirect_status, method):
270275
self.assertEqual(do_req(303, 'PUT'), ('', 'GET'))
271276

272277
# 301 and 302 turn POST only into a GET
278+
# XXX: we should also test if the Content-Type and Content-Length headers are removed
273279
self.assertEqual(do_req(301, 'POST'), ('', 'GET'))
274280
self.assertEqual(do_req(301, 'HEAD'), ('', 'HEAD'))
275281
self.assertEqual(do_req(302, 'POST'), ('', 'GET'))
@@ -313,6 +319,31 @@ def test_cookiejar(self):
313319
data = ydl.urlopen(sanitized_Request(f'http://127.0.0.1:{self.http_port}/headers')).read()
314320
self.assertIn(b'Cookie: test=ytdlp', data)
315321

322+
def test_passed_cookie_header(self):
323+
# We should accept a Cookie header being passed as in normal headers and handle it appropriately.
324+
with FakeYDL() as ydl:
325+
# Specified Cookie header should be used
326+
res = ydl.urlopen(
327+
sanitized_Request(f'http://127.0.0.1:{self.http_port}/headers',
328+
headers={'Cookie': 'test=test'})).read().decode('utf-8')
329+
self.assertIn('Cookie: test=test', res)
330+
331+
# Specified Cookie header should be removed on any redirect
332+
res = ydl.urlopen(
333+
sanitized_Request(f'http://127.0.0.1:{self.http_port}/308-to-headers', headers={'Cookie': 'test=test'})).read().decode('utf-8')
334+
self.assertNotIn('Cookie: test=test', res)
335+
336+
# Specified Cookie header should override global cookiejar for that request
337+
ydl.cookiejar.set_cookie(http.cookiejar.Cookie(
338+
version=0, name='test', value='ytdlp', port=None, port_specified=False,
339+
domain='127.0.0.1', domain_specified=True, domain_initial_dot=False, path='/',
340+
path_specified=True, secure=False, expires=None, discard=False, comment=None,
341+
comment_url=None, rest={}))
342+
343+
data = ydl.urlopen(sanitized_Request(f'http://127.0.0.1:{self.http_port}/headers', headers={'Cookie': 'test=test'})).read()
344+
self.assertNotIn(b'Cookie: test=ytdlp', data)
345+
self.assertIn(b'Cookie: test=test', data)
346+
316347
def test_no_compression_compat_header(self):
317348
with FakeYDL() as ydl:
318349
data = ydl.urlopen(

Diff for: yt_dlp/utils/_utils.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -1556,7 +1556,12 @@ def redirect_request(self, req, fp, code, msg, headers, newurl):
15561556

15571557
new_method = req.get_method()
15581558
new_data = req.data
1559-
remove_headers = []
1559+
1560+
# Technically the Cookie header should be in unredirected_hdrs,
1561+
# however in practice some may set it in normal headers anyway.
1562+
# We will remove it here to prevent any leaks.
1563+
remove_headers = ['Cookie']
1564+
15601565
# A 303 must either use GET or HEAD for subsequent request
15611566
# https://datatracker.ietf.org/doc/html/rfc7231#section-6.4.4
15621567
if code == 303 and req.get_method() != 'HEAD':
@@ -1573,7 +1578,7 @@ def redirect_request(self, req, fp, code, msg, headers, newurl):
15731578
new_data = None
15741579
remove_headers.extend(['Content-Length', 'Content-Type'])
15751580

1576-
new_headers = {k: v for k, v in req.headers.items() if k.lower() not in remove_headers}
1581+
new_headers = {k: v for k, v in req.headers.items() if k.title() not in remove_headers}
15771582

15781583
return urllib.request.Request(
15791584
newurl, headers=new_headers, origin_req_host=req.origin_req_host,

0 commit comments

Comments
 (0)