CVE-2026-12003
Description
Python's in-tree path detection on Windows can be triggered by a low-privilege user creating a landmark file outside the install directory, leading to arbitrary code execution.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Python's in-tree path detection on Windows can be triggered by a low-privilege user creating a landmark file outside the install directory, leading to arbitrary code execution.
Vulnerability
A vulnerability exists in Python's in-tree path detection mechanism on Windows. When Python is built with a VPATH variable set to ..\.. (as in the PCbuild/ directory), the interpreter searches for the landmark file Modules\setup.local relative to the VPATH. This path resolves to a directory two levels above the Python installation directory, which on Windows is often the root of the system drive (e.g., C:\). A low-privilege user can create this landmark file and an accompanying Lib folder, causing Python to use an alternative sys.path when executed by a higher-privilege user. This affects Python versions that include the VPATH fallback (all versions up to and including 3.14) when installed via the legacy EXE installer to the default all-users location [1][2].
Exploitation
An attacker needs only the ability to create files and folders in the root directory of the OS drive (e.g., C:\), which is allowed by default for all users on Windows. The attacker creates the directory C:\Modules and places a file setup.local inside it. Additionally, the attacker creates a Lib folder at C:\Lib containing malicious Python modules. When a privileged user runs Python from an affected installation, the interpreter detects the landmark and adds C:\Lib to sys.path, allowing the attacker's modules to be imported and executed with the privileges of the user running Python [2].
Impact
Successful exploitation allows an attacker to execute arbitrary Python code with the privileges of the user running the Python interpreter. If that user is an administrator, the attacker gains full control over the system. The impact is privilege escalation from a low-privilege user to a higher-privilege user, potentially leading to remote code execution if Python is invoked by a service or scheduled task [2].
Mitigation
The recommended mitigation is to migrate away from the legacy EXE installer and use the new Python install manager to install for the current user, which prevents other users from modifying the installation directory. Alternatively, administrators can preemptively create and restrict access to the Modules directory in the root of the system drive. Python 3.13 and 3.14 will receive updated legacy installers that remove the VPATH fallback; earlier versions will receive source-level fixes only [1][2].
AI Insight generated on Jun 16, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
2(expand)+ 1 more
- (no CPE)
- (no CPE)range: 3.11, 3.12, 3.13, 3.14-dev
Patches
1672f2cb9268aMerge 70871e1085d2bad5e78c6cc056474bb35a501316 into 0777a58d8012bbdd0d72654b56f9112686ae6ff0
3 files changed · +10 −11
Makefile.pre.in+2 −0 modified@@ -1616,6 +1616,8 @@ Programs/_bootstrap_python.o: Programs/_bootstrap_python.c $(BOOTSTRAP_HEADERS) _bootstrap_python: $(LIBRARY_OBJS_OMIT_FROZEN) Programs/_bootstrap_python.o Modules/getpath.o Modules/Setup.local $(LINKCC) $(PY_LDFLAGS_NOLTO) -o $@ $(LIBRARY_OBJS_OMIT_FROZEN) \ Programs/_bootstrap_python.o Modules/getpath.o $(LIBS) $(MODLIBS) $(SYSLIBS) + # Dummy pybuilddir.txt is needed for _bootstrap_python to be runnable + @echo "none" > ./pybuilddir.txt ############################################################################
Misc/NEWS.d/next/Security/2026-06-16-14-58-02.gh-issue-151544._bexVy.rst+4 −0 added@@ -0,0 +1,4 @@ +:file:`Modules/Setup.local` is no longer used as a landmark to discover +whether Python is running in a source tree, as it could potentially affect +actual installs. The :file:`pybuilddir.txt` file is now the sole indicator +of running in a source tree.
Modules/getpath.py+4 −11 modified@@ -129,8 +129,7 @@ # checked by looking for the BUILDDIR_TXT file, which contains the # relative path to the platlib dir. The executable_dir value is # derived from joining the VPATH preprocessor variable to the -# directory containing pybuilddir.txt. If it is not found, the -# BUILD_LANDMARK file is found, which is part of the source tree. +# directory containing pybuilddir.txt. # prefix is then found by searching up for a file that should only # exist in the source tree, and the stdlib dir is set to prefix/Lib. @@ -177,7 +176,6 @@ if os_name == 'posix' or os_name == 'darwin': BUILDDIR_TXT = 'pybuilddir.txt' - BUILD_LANDMARK = 'Modules/Setup.local' DEFAULT_PROGRAM_NAME = f'python{VERSION_MAJOR}' STDLIB_SUBDIR = f'{platlibdir}/python{VERSION_MAJOR}.{VERSION_MINOR}{ABI_THREAD}' STDLIB_LANDMARKS = [f'{STDLIB_SUBDIR}/os.py', f'{STDLIB_SUBDIR}/os.pyc'] @@ -190,7 +188,6 @@ elif os_name == 'nt': BUILDDIR_TXT = 'pybuilddir.txt' - BUILD_LANDMARK = f'{VPATH}\\Modules\\Setup.local' DEFAULT_PROGRAM_NAME = f'python' STDLIB_SUBDIR = 'Lib' STDLIB_LANDMARKS = [f'{STDLIB_SUBDIR}\\os.py', f'{STDLIB_SUBDIR}\\os.pyc'] @@ -513,13 +510,9 @@ def search_up(prefix, *landmarks, test=isfile): platstdlib_dir = real_executable_dir build_prefix = joinpath(real_executable_dir, VPATH) except (FileNotFoundError, PermissionError): - if isfile(joinpath(real_executable_dir, BUILD_LANDMARK)): - build_prefix = joinpath(real_executable_dir, VPATH) - if os_name == 'nt': - # QUIRK: Windows builds need platstdlib_dir to be the executable - # dir. Normally the builddir marker handles this, but in this - # case we need to correct manually. - platstdlib_dir = real_executable_dir + # We used to check for an alternate landmark here, but now we require + # BUILDDIR_TXT to exist. (gh-151544; CVE-2026-12003) + pass if build_prefix: if os_name == 'nt':
Vulnerability mechanics
Synthesis attempt was rejected by the grounding validator. Re-run pending.
References
3News mentions
0No linked articles in our index yet.