https://github.com/python/cpython/commit/0615b5c0d9ee3854bc50fe2bcc68e6799cead14a
commit: 0615b5c0d9ee3854bc50fe2bcc68e6799cead14a
branch: main
author: Gregory P. Smith <[email protected]>
committer: gpshead <[email protected]>
date: 2026-10-23T17:20:53Z
summary:

gh-160420: Reject drive letters in ZoneInfo key components on Windows 
(GH-160421)

A key such as "America/C:\file" passed validation, and the tzdata
loader then joined "C:\file" to the package directory, which replaced it.

ANT-2026-IZMAOLCQ

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 40696b09d95719..6d00040babbd72 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
@@ -13,9 +14,11 @@
 import shutil
 import struct
 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
@@ -2016,6 +2019,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 3661c837daa0a4..7b6396444fd911 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 00000000000000..2255056dac577e
--- /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]

Reply via email to