https://github.com/python/cpython/commit/c7a52036a8dbb35294f9d4468dbf6c2953341903 commit: c7a52036a8dbb35294f9d4468dbf6c2953341903 branch: 3.14 author: Miss Islington (bot) <[email protected]> committer: hugovk <[email protected]> date: 2026-10-27T10:52:03+02:00 summary:
[3.14] gh-160420: Reject drive letters in ZoneInfo key components on Windows (GH-160421) (#160448) Co-authored-by: Gregory P. Smith <[email protected]> files: A Misc/NEWS.d/next/Security/2026-10-22-08-05-32.gh-issue-160420.tZ9dRv.rst M Lib/test/test_zoneinfo/test_zoneinfo.py M Lib/zoneinfo/_tzpath.py diff --git a/Lib/test/test_zoneinfo/test_zoneinfo.py b/Lib/test/test_zoneinfo/test_zoneinfo.py index 075ead435bd28b8..6f87cc91af04551 100644 --- a/Lib/test/test_zoneinfo/test_zoneinfo.py +++ b/Lib/test/test_zoneinfo/test_zoneinfo.py @@ -6,6 +6,7 @@ import importlib.metadata import io import json +import ntpath import os import pathlib import pickle @@ -14,9 +15,11 @@ import struct import sys import tempfile +import types import unittest from datetime import date, datetime, time, timedelta, timezone from functools import cached_property +from unittest import mock from test.support import MISSING_C_DOCSTRINGS from test.support.os_helper import EnvironmentVarGuard, FakePath @@ -2017,6 +2020,38 @@ def test_tzpath_type_error(self): with self.assertRaises(TypeError): self.module.reset_tzpath(bad_value) + def test_validate_key_windows_paths(self): + # Check the key validation with Windows path rules on every platform. + tzpath = self.module._tzpath + base = ntpath.normpath(ntpath.join("_", "_"))[:-1] + fake_os = types.SimpleNamespace(path=ntpath) + + good_keys = [ + "UTC", + "America/New_York", + "America/Argentina/Buenos_Aires", + "Etc/GMT+1", + ] + bad_keys = [ + "C:\\Windows\\win.ini", + "America/C:\\Windows\\win.ini", # Drive in a component + "America/C:/Windows/win.ini", + "America/D:secret", # Drive-relative component + "America/Argentina/D:secret", + "America/\\Windows\\win.ini", # Rooted component + "America/\\\\server\\share\\file", # UNC component + ] + + with mock.patch.object(tzpath, "os", fake_os): + for key in good_keys: + with self.subTest(key=key): + tzpath._validate_tzfile_path(key, _base=base) + + for key in bad_keys: + with self.subTest(key=key): + with self.assertRaises(ValueError): + tzpath._validate_tzfile_path(key, _base=base) + def test_tzpath_attribute(self): tzpath_0 = [f"{DRIVE}/one", f"{DRIVE}/two"] tzpath_1 = [f"{DRIVE}/three"] diff --git a/Lib/zoneinfo/_tzpath.py b/Lib/zoneinfo/_tzpath.py index 177d32c35eff296..f2be390c4ad6e69 100644 --- a/Lib/zoneinfo/_tzpath.py +++ b/Lib/zoneinfo/_tzpath.py @@ -111,6 +111,17 @@ def _validate_tzfile_path(path, _base=_TEST_PATH): f"ZoneInfo keys must refer to subdirectories of TZPATH, got: {path}" ) + # load_tzdata() joins the last "/"-separated component of the key to the + # tzdata package directory on its own. On Windows a component with a + # drive or root, such as "C:\\file" in "America/C:\\file", would replace + # that directory instead of being looked up inside it. + for component in path.split("/"): + drive, root, _ = os.path.splitroot(component) + if drive or root: + raise ValueError( + f"ZoneInfo keys must not contain drives or roots, got: {path}" + ) + del _TEST_PATH diff --git a/Misc/NEWS.d/next/Security/2026-10-22-08-05-32.gh-issue-160420.tZ9dRv.rst b/Misc/NEWS.d/next/Security/2026-10-22-08-05-32.gh-issue-160420.tZ9dRv.rst new file mode 100644 index 000000000000000..2255056dac577e7 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-10-22-08-05-32.gh-issue-160420.tZ9dRv.rst @@ -0,0 +1,4 @@ +Fix :class:`zoneinfo.ZoneInfo` on Windows accepting keys in which a component +after a ``/`` starts with a drive letter, such as ``America/C:\file``. Such a +key could open a file outside the ``tzdata`` package; it now raises +:exc:`ValueError`. _______________________________________________ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3//lists/python-checkins.python.org Member address: [email protected]
