Skip to content

With LOCALAPPDATA unset, install_dir resolves to the current directory; auto-install then deletes registry entries and shortcuts of the real installs #427

Open

Description

@samuellessa-afk

Install source and version

  • Installed from the Windows Store
  • Installed with the MSIX from python.org
  • Installed with the MSI from python.org
  • Installed with winget install 9NQ7512CXL7T

Version: 26.4 (PythonSoftwareFoundation.PythonManager_26.4.240.0_x64), Windows 11 Pro 25H2 (10.0.26200)

Describe the bug
When py is started with an environment that lacks LOCALAPPDATA (e.g. a tool that spawns processes with a minimal environment), the built-in default install_dir = %LocalAppData%\Python resolves to <current directory>\Python. py then sees no runtimes, automatically installs the default runtime into the current directory, and the follow-up registration cleanup removes the PEP 514 registry keys, Start menu shortcuts and ARP entries of the runtimes that are really installed under %LocalAppData%\Python, because they are not visible from the wrong root. It leaves a PythonCore\3.15 key pointing into the arbitrary directory.

To Reproduce
With 3.13 and 3.14 installed normally, from Git Bash (any way of starting a process with only PATH and SYSTEMROOT set reproduces it):

mkdir /tmp/pm-repro && cd /tmp/pm-repro
env -i PATH="$PATH" SYSTEMROOT="$SYSTEMROOT" py list -vv
# Setting config install_dir to C:\Users\<user>\AppData\Local\Temp\pm-repro\Python
# Setting config download_dir to C:\Users\<user>\AppData\Local\Temp\pm-repro\Python\_cache
# Setting config global_dir to C:\Users\<user>\AppData\Local\Temp\pm-repro\Python\bin

env -i PATH="$PATH" SYSTEMROOT="$SYSTEMROOT" py -I -c "print(1)"

Log of the second command (paths shortened):

BEGIN install_command.execute: []
Reading installs from <cwd>\Python
Found 0 installs
>  Installing Python 3.15.0.
>> Extracting ...\bundled\pythoncore-3.15-64-3.15.0.zip to <cwd>\Python\pythoncore-3.15-64
Cleaning up registry entries
Skipping HKEY_CURRENT_USER\Software\Python\Astral\CPython3.12.14
Removing HKEY_CURRENT_USER\Software\Python\PythonCore\3.13
Removing HKEY_CURRENT_USER\Software\Python\PythonCore\3.14
Cleaning up Start menu shortcuts
Removing ...\Start Menu\Programs\Python\Python 3.13\...
Removing ...\Start Menu\Programs\Python\Python 3.14\...
Removing ARP registration for pymanager-pythoncore-3.13-64
Removing ARP registration for pymanager-pythoncore-3.14-64

The log file itself was also written to the current directory (presumably because TEMP was unset too). With automatic_install disabled by policy, the second command fails with No runtimes are installed instead, but py list -vv still creates <cwd>\Python\_cache\last_welcome.txt.

Expected behavior

  • If %LocalAppData% cannot be expanded, resolve the folder from the OS (SHGetKnownFolderPath(FOLDERID_LocalAppData) does not depend on environment variables), or fail with a clear error. It should not silently fall back to the current directory.
  • The registry/shortcut/ARP cleanup should not remove entries for runtimes it cannot see because its root changed. Only removing keys whose InstallPath lies under the current install_dir (or whose target no longer exists) would make this safe.

Additional context

  • py install --refresh run with the normal environment restored the registry, shortcuts and ARP entries.
  • Workaround in use: an HKLM\Software\Policies\Python\PyManager base_config pointing to a JSON file with absolute install_dir, download_dir, global_dir, logs_dir and user_config. With it, the same env -i ... py -I -c command runs the installed 3.14 normally and touches nothing.
  • user_config (%AppData%\Python\PyManager.json) has the same fallback: without APPDATA it resolves to <cwd>\Python\PyManager.json, and a file there would replace the configured paths.
  • Possibly related: Please support fully managed Python runtimes at explicitly selected drive/path locations #423 (explicit install locations), but that issue does not cover this failure mode.

Activity

  1. zooba commented on Oct 13, 2026

    @zooba
    Member

    We can probably make the config loader warn about empty environment variables in cases where there's string concatenation involved, and define 1-2 fallback lookups.

    A process environment missing standard variables like these is essentially corrupted, from our POV, so there's no security angle here (just noting it explicitly - if this had been reported as a security issue it would be immediately made public on that basis).

    The "explicitly selected location" feature request is entirely unrelated.

  2. zooba commented on Oct 13, 2026

    @zooba
    Member

    For reference, this is the function that needs enhancing to handle missing environment variables:

    def _expand_vars(v, env):
    import re
    def _sub(m):
    v2 = env.get(m.group(1))
    if v2:
    return v2 + (m.group(2) or "")
    return ""
    v2 = re.sub(r"%(.*?)%([\\/])?", _sub, v)
    return v2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions