Dear Debian Security Team, I would like to hand in a patch for CVE-2025-68146 in python3-filelock in trixie.
Upstream fixed the issue in a patch [1] as mentioned in #1123510 [2]. Debian unstable already has included the fix via 3.20.2. It is easily backported to the version in trixie, 3.20.0. The patch contains more background information about the nature of the fix. I am attaching a debdiff for review. Do you think the upload fixing this should target trixie-security or trixie? I am quite new to fixing things in stable. Best regards Sascha [1] https://github.com/tox-dev/filelock/pull/461 [2] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1123510
diff -Nru python-filelock-3.18.0/debian/changelog python-filelock-3.18.0/debian/changelog --- python-filelock-3.18.0/debian/changelog 2025-03-22 00:19:37.000000000 +0100 +++ python-filelock-3.18.0/debian/changelog 2026-01-07 14:16:28.000000000 +0100 @@ -1,3 +1,12 @@ +python-filelock (3.18.0-1+deb13u1) trixie; urgency=medium + + * Add patch: cve-2025-68146.patch + This addresses CVE-2025-68146 by including the patch from upstream. + (commit e84510eac948b5b6027b24025f421a650cbd9749) + Closes: #112351 + + -- Sascha Steinbiss <[email protected]> Wed, 07 Jan 2026 14:16:28 +0100 + python-filelock (3.18.0-1) unstable; urgency=medium * New upstream release. diff -Nru python-filelock-3.18.0/debian/patches/cve-2025-68146.patch python-filelock-3.18.0/debian/patches/cve-2025-68146.patch --- python-filelock-3.18.0/debian/patches/cve-2025-68146.patch 1970-01-01 01:00:00.000000000 +0100 +++ python-filelock-3.18.0/debian/patches/cve-2025-68146.patch 2026-01-07 14:16:21.000000000 +0100 @@ -0,0 +1,101 @@ +From e84510eac948b5b6027b24025f421a650cbd9749 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= <[email protected]> +Date: Mon, 15 Dec 2025 08:49:14 -0800 +Subject: [PATCH] Fix TOCTOU symlink vulnerability in lock file creation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +A race condition existed between checking if the lock file exists and opening it with O_TRUNC, allowing +local attackers to create a symlink pointing to victim files. When the lock was acquired, os.open() would +follow the symlink and truncate the target file, causing data loss or corruption. + +The vulnerability affected both Unix and Windows platforms and cascaded through dependent libraries: +- virtualenv: Could overwrite user configs with virtualenv metadata, leaking file contents +- PyTorch: Could truncate CPU ISA cache causing crashes, or corrupt compiled model checkpoints preventing + model loading (DoS for ML pipelines) + +Unix/Linux/macOS fix: +- Add O_NOFOLLOW flag to os.open() call in UnixFileLock._acquire() +- System returns ELOOP error if lock path is a symlink, preventing the attack + +Windows fix: +- Use GetFileAttributesW API via ctypes to detect reparse points (symlinks/junctions) +- Refuse to open lock file if FILE_ATTRIBUTE_REPARSE_POINT flag is set +- Raises OSError before attempting to open, closing the race window + +This addresses CWE-362 (Race Condition), CWE-367 (TOCTOU), and CWE-59 (Link Following). + +Reported-by: @tsigouris007 +Signed-off-by: Bernát Gábor <[email protected]> +--- + src/filelock/_unix.py | 2 +- + src/filelock/_windows.py | 38 ++++++++++++++++++++++++++++++++++++++ + 2 files changed, 39 insertions(+), 1 deletion(-) + +--- a/src/filelock/_unix.py ++++ b/src/filelock/_unix.py +@@ -38,7 +38,7 @@ + + def _acquire(self) -> None: + ensure_directory_exists(self.lock_file) +- open_flags = os.O_RDWR | os.O_TRUNC ++ open_flags = os.O_RDWR | os.O_TRUNC | os.O_NOFOLLOW + if not Path(self.lock_file).exists(): + open_flags |= os.O_CREAT + fd = os.open(self.lock_file, open_flags, self._context.mode) +--- a/src/filelock/_windows.py ++++ b/src/filelock/_windows.py +@@ -11,7 +11,38 @@ + from ._util import ensure_directory_exists, raise_on_not_writable_file + + if sys.platform == "win32": # pragma: win32 cover ++ import ctypes + import msvcrt ++ from ctypes import wintypes ++ ++ # Windows API constants for reparse point detection ++ FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400 ++ INVALID_FILE_ATTRIBUTES = 0xFFFFFFFF ++ ++ # Load kernel32.dll ++ _kernel32 = ctypes.WinDLL("kernel32", use_last_error=True) ++ _kernel32.GetFileAttributesW.argtypes = [wintypes.LPCWSTR] ++ _kernel32.GetFileAttributesW.restype = wintypes.DWORD ++ ++ def _is_reparse_point(path: str) -> bool: ++ """ ++ Check if a path is a reparse point (symlink, junction, etc.) on Windows. ++ ++ :param path: Path to check ++ :return: True if path is a reparse point, False otherwise ++ :raises OSError: If GetFileAttributesW fails for reasons other than file-not-found ++ """ ++ attrs = _kernel32.GetFileAttributesW(path) ++ if attrs == INVALID_FILE_ATTRIBUTES: ++ # File doesn't exist yet - that's fine, we'll create it ++ err = ctypes.get_last_error() ++ if err == 2: # noqa: PLR2004 # ERROR_FILE_NOT_FOUND ++ return False ++ if err == 3: # noqa: PLR2004 # ERROR_PATH_NOT_FOUND ++ return False ++ # Some other error - let caller handle it ++ return False ++ return bool(attrs & FILE_ATTRIBUTE_REPARSE_POINT) + + class WindowsFileLock(BaseFileLock): + """Uses the :func:`msvcrt.locking` function to hard lock the lock file on Windows systems.""" +@@ -19,6 +50,13 @@ + def _acquire(self) -> None: + raise_on_not_writable_file(self.lock_file) + ensure_directory_exists(self.lock_file) ++ ++ # Security check: Refuse to open reparse points (symlinks, junctions) ++ # This prevents TOCTOU symlink attacks (CVE-TBD) ++ if _is_reparse_point(self.lock_file): ++ msg = f"Lock file is a reparse point (symlink/junction): {self.lock_file}" ++ raise OSError(msg) ++ + flags = ( + os.O_RDWR # open for read and write + | os.O_CREAT # create file if not exists diff -Nru python-filelock-3.18.0/debian/patches/series python-filelock-3.18.0/debian/patches/series --- python-filelock-3.18.0/debian/patches/series 1970-01-01 01:00:00.000000000 +0100 +++ python-filelock-3.18.0/debian/patches/series 2026-01-07 14:16:15.000000000 +0100 @@ -0,0 +1 @@ +cve-2025-68146.patch
OpenPGP_signature.asc
Description: OpenPGP digital signature

