From 6c91b1607d5358eb9e91e389b8894e00b0872593 Mon Sep 17 00:00:00 2001 From: dieter Date: Wed, 27 Sep 2023 07:12:00 +0200 Subject: [PATCH] base inline/attachment logic for CVE-2023-42458 on the media type proper (ignoring parameters and whitespace) [skip ci] --- CHANGES.rst | 4 ++++ src/OFS/Image.py | 10 +++++++++- src/OFS/tests/testFileAndImage.py | 18 ++++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index 54bf47ddae..cef361ef3b 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -13,6 +13,10 @@ https://github.com/zopefoundation/Zope/blob/4.x/CHANGES.rst - Update to newest compatible versions of dependencies. +- Base the inline/attachment logic developped for CVE-2023-42458 + on the media type proper (ignoring parameters and leading/trailing + whitespace). + 5.8.5 (2023-09-21) ------------------ diff --git a/src/OFS/Image.py b/src/OFS/Image.py index bb9c428967..0b2aaccfd7 100644 --- a/src/OFS/Image.py +++ b/src/OFS/Image.py @@ -474,7 +474,7 @@ def _range_request_handler(self, REQUEST, RESPONSE): def _should_force_download(self): # If this returns True, the caller should set a # Content-Disposition header with filename. - mimetype = self.content_type + mimetype = extract_media_type(self.content_type) if not mimetype: return False if self.use_denylist: @@ -1170,3 +1170,11 @@ def __bytes__(self): _next = self.next return b''.join(r) + + +def extract_media_type(content_type): + """extract the proper media type from *content_type*. + + Ignore parameters and leading/trailing whitespace. + """ + return content_type and content_type.split(";", 1)[0].strip() diff --git a/src/OFS/tests/testFileAndImage.py b/src/OFS/tests/testFileAndImage.py index 17d65fd8f4..fab377bea7 100644 --- a/src/OFS/tests/testFileAndImage.py +++ b/src/OFS/tests/testFileAndImage.py @@ -433,6 +433,18 @@ def testViewImageOrFile_with_denylist(self): "attachment; filename*=UTF-8''file.svg", ) + def testViewImageOrFile_with_denylist_and_ct_param(self): + request = self.app.REQUEST + response = request.RESPONSE + self.file.use_denylist = True + self.file.content_type += ";charset=utf-8" + result = self.file.index_html(request, response) + self.assertEqual(result, self.data) + self.assertEqual( + response.getHeader("Content-Disposition"), + "attachment; filename*=UTF-8''file.svg", + ) + def testViewImageOrFile_with_empty_denylist(self): request = self.app.REQUEST response = request.RESPONSE @@ -442,6 +454,12 @@ def testViewImageOrFile_with_empty_denylist(self): self.assertEqual(result, self.data) self.assertIsNone(response.getHeader("Content-Disposition")) + def test_extract_media_type(self): + extract = OFS.Image.extract_media_type + self.assertIsNone(extract(None)) + self.assertEqual(extract("text/plain"), "text/plain") + self.assertEqual(extract(" text/plain ; charset=utf-8"), "text/plain") + class FileEditTests(Testing.ZopeTestCase.FunctionalTestCase): """Browser testing ..Image.File"""