From 5bd9f306f25a676781dc5d6071657d32ba02f99e Mon Sep 17 00:00:00 2001 From: icanhasmath Date: Wed, 28 Oct 2026 00:56:42 -0500 Subject: [PATCH] gh-159428: Don't read mimetypes.knownfiles by default on Windows (CVE-2024-3220) Backport of python/cpython gh-159428 (GH-159445; the 3.10.22.1 port is f3c18820409) to 2.7.18.x. mimetypes.init() reads the registry on Windows and then every file in knownfiles. Those are Unix paths ("/etc/mime.types", ...), which on Windows resolve to the root of the current drive (C:\etc\mime.types). Unprivileged users can usually create such files, and so could register arbitrary MIME types for every Python process on the machine, e.g. to change what SimpleHTTPServer serves a file as. knownfiles is now empty on Windows; only the registry is used by default. Callers can still pass files to init() or add to knownfiles themselves. 2.7.18.x: test_mimetypes empties mimetypes.knownfiles at import for isolation, so the test keeps a reference to the default list taken before that line; the non-Windows check lives in a new KnownfilesTestCase registered in test_main(). Co-Authored-By: Claude Opus 5.5 --- Lib/mimetypes.py | 28 +++++++++++++++++----------- Lib/test/test_mimetypes.py | 13 +++++++++++++ 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py index afc053f135ddfba..92b0a414c2e5fef 100644 --- a/Lib/mimetypes.py +++ b/Lib/mimetypes.py @@ -37,17 +37,23 @@ "add_type","read_mime_types","init" ] -knownfiles = [ - "/etc/mime.types", - "/etc/httpd/mime.types", # Mac OS X - "/etc/httpd/conf/mime.types", # Apache - "/etc/apache/mime.types", # Apache 1 - "/etc/apache2/mime.types", # Apache 2 - "/usr/local/etc/httpd/conf/mime.types", - "/usr/local/lib/netscape/mime.types", - "/usr/local/etc/httpd/conf/mime.types", # Apache 1.2 - "/usr/local/etc/mime.types", # Apache 1.3 - ] +if sys.platform == "win32": + # The default paths would resolve to the root of the current drive on Windows + # (e.g. C:\etc\mime.types), which unprivileged users can usually create. + # Only the registry is used by default. + knownfiles = [] +else: + knownfiles = [ + "/etc/mime.types", + "/etc/httpd/mime.types", # Mac OS X + "/etc/httpd/conf/mime.types", # Apache + "/etc/apache/mime.types", # Apache 1 + "/etc/apache2/mime.types", # Apache 2 + "/usr/local/etc/httpd/conf/mime.types", + "/usr/local/lib/netscape/mime.types", + "/usr/local/etc/httpd/conf/mime.types", # Apache 1.2 + "/usr/local/etc/mime.types", # Apache 1.3 + ] inited = False _db = None diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py index e9a7216d1c6c214..2c8b7fd2137dee6 100644 --- a/Lib/test/test_mimetypes.py +++ b/Lib/test/test_mimetypes.py @@ -8,6 +8,8 @@ from test import test_support # Tell it we don't know about external files: +# The default list, before it is emptied below for test isolation. +knownfiles = mimetypes.knownfiles mimetypes.knownfiles = [] mimetypes.inited = False mimetypes._default_mime_types() @@ -67,6 +69,12 @@ def test_guess_all_types(self): eq(all, []) +class KnownfilesTestCase(unittest.TestCase): + @unittest.skipIf(sys.platform == "win32", "non-Windows only") + def test_default_knownfiles(self): + self.assertIn("/etc/mime.types", knownfiles) + + @unittest.skipUnless(sys.platform.startswith("win"), "Windows only") class Win32MimeTypesTestCase(unittest.TestCase): def setUp(self): @@ -90,6 +98,10 @@ def test_registry_parsing(self): eq(db.guess_type("image.jpg"), ("image/jpeg", None)) eq(db.guess_type("image.png"), ("image/png", None)) + def test_default_knownfiles(self): + # CVE-2024-3220: the Unix paths would resolve to e.g. C:\etc\mime.types + self.assertEqual(knownfiles, []) + def test_non_latin_extension(self): import _winreg @@ -163,6 +175,7 @@ def __getattr__(self, name): def test_main(): test_support.run_unittest(MimeTypesTestCase, + KnownfilesTestCase, Win32MimeTypesTestCase )