#Summary

CVE-2026-53940 is a path traversal vulnerability in Conda versions prior to 26.5.2 that allows arbitrary file write with code execution. A malicious noarch:python package can write executable files outside the installation prefix or overwrite existing entry points like bin/pip. When an attacker-controlled entry point is invoked, it runs arbitrary Python code with the installing user's privileges - typically root in containerized environments. CVSS score: 8.8 HIGH.

#Am I affected?

#How to check

Check your conda version:

conda --version
Output Verdict
conda 26.5.1 or earlier Vulnerable
conda 26.5.2 or later Patched

If the output is unclear, the real verification is whether the entry-point parser validates input. Run this in your conda base environment:

python -c "import conda.common.path.python as p; import inspect; print('PATCHED' if 'ValueError' in inspect.getsource(p.parse_entry_point_def) or hasattr(p, 'is_valid_import_path') else 'VULNERABLE')"

#Fix and mitigation

#Root cause analysis

#Vulnerable code path

The vulnerability spans four stages in conda's entry-point handling. A noarch:python package declares console scripts in its metadata file info/link.json:

{
  "package_metadata_version": 1,
  "noarch": {"type": "python", "entry_points": ["mytool = mypkg.cli:main"]}
}

This metadata is user-controlled. Unlike files inside the package payload, it is never extracted or validated.

Step 1: The parser does no validation. The function parse_entry_point_def in conda/common/path/python.py (lines 40-44, v26.5.1) is the entire parsing layer:

def parse_entry_point_def(ep_definition):
    cmd_mod, func = ep_definition.rsplit(":", 1)
    command, module = cmd_mod.rsplit("=", 1)
    command, module, func = command.strip(), module.strip(), func.strip()
    return command, module, func

The command component may contain path separators, traversal segments (..), NUL bytes, or newlines - none are checked.

Step 2: The command is embedded in a path. The function CreatePythonEntryPointAction.create_actions in conda/core/path_actions.py (lines 824-863) builds:

target_short_path = f"{BIN_DIRECTORY}/{command}"

where BIN_DIRECTORY is "bin" on Unix or "Scripts" on Windows. This is a raw f-string concatenation with no path normalization.

Step 3: The join preserves traversal segments. The function PrefixPathAction.target_full_path (lines 193-209) calls:

return join(trgt, win_path_ok(shrt_pth))

os.path.join preserves .. segments literally. They are only resolved by the kernel at open() time, after every conda check has passed. The action's verify() method is a no-op.

Step 4: The file is written with execute permission. The function create_python_entry_point in conda/gateways/disk/create.py (lines 130-162) writes the file:

with open(target_full_path, mode="w", encoding="utf-8") as fo:
    fo.write(pyscript)
...
make_executable(target_full_path)

The lexists guard before this is not a security control. The shipped default path_conflict: clobber overwrites existing files silently with no warning.

#Secondary primitive: template injection

The module and func fields from the entry-point string are interpolated verbatim into the generated wrapper script:

python_entry_point_template = """
from %(module)s import %(import_name)s

if __name__ == '__main__':
    sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?