CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-113720

CVE-2026-113720: Local Permission Inheritance Vulnerability in virtualenv

Amit Schendel
Amit Schendel
Senior Security Researcher

Oct 24, 2026·5 min read·5 visits

Executive Summary (TL;DR)

virtualenv < 21.14.9 uses shutil.copy() when seeding environments from the app-data cache, preserving original file modes and bypassing process umask. If the cache was populated under a loose umask, resulting virtual environment files may remain world- or group-writable, allowing local privilege escalation via code injection.

virtualenv prior to version 21.14.9 contains a local permission inheritance vulnerability in its app-data copy seeder. Due to the reliance on Python's standard shutil.copy() function, permissions from cached packages are replicated directly onto newly created virtual environment files, ignoring the active process umask and allowing unprivileged local attackers to inject code.

Vulnerability Overview

virtualenv is a standard utility in Python ecosystem workflows used to create isolated execution environments. To minimize overhead and network operations during setup, virtualenv utilizes an app-data disk cache that stores pre-downloaded wheel files and seed packages.

When creating new environments, virtualenv copies these cached artifacts into the destination directory structure. Prior to version 21.14.9, the copy mechanism preserved the exact file permission mode bits (stat.st_mode) of the cached source files. This design ignored the current process's file creation mask (umask).

If the centralized app-data cache was populated when a loose umask (e.g., 000 or 002) was active, cached files inherited permissive file mode bits such as 0666 or 0777. When subsequent environments were constructed, these permissive mode bits were retained on executable scripts and package modules, exposing the virtual environment to unauthorized local modifications.

Root Cause Analysis

The root cause stems from reliance on shutil.copy() and shutil.copytree() in virtualenv's synchronization logic (src/virtualenv/util/path/_sync.py). Under POSIX systems, shutil.copy() delegates mode setting to shutil.copymode(), which explicitly reads the source file's st_mode and applies it to the target file via os.chmod().

# Vulnerable path handling prior to 21.14.9
def copy(src: Path, dest: Path) -> None:
    LOGGER.debug("copy %s", _Debug(src, dest))
    method = copytree if src.is_dir() else shutil.copy
    method(str(src), str(dest))

By executing shutil.copymode(), virtualenv explicitly overrode the operating system's normal process file creation mask behavior. Files created with standard file-creation syscalls respect the active process umask by calculating mode & ~umask. In contrast, shutil.copymode() retroactively applies permission bits directly from the source stat structure.

This architecture created a cross-context permission leak. The security boundary of a newly created virtual environment was bound to the permissions of historical cache generation rather than the calling process's active system policy.

Code Analysis & Fix Verification

To resolve the vulnerability in commit 35f0b33562790176dd186d0a3c517af3acc7a0e1, the maintainers eliminated standard shutil.copy() calls in favor of a low-level custom file transfer routine _copy_file().

# Fixed copy implementation in src/virtualenv/util/path/_sync.py
def _copy_file(src: Path, dest: Path) -> None:
    ensure_safe_to_do(src, dest)
    mode: Final = 0o755 if src.stat().st_mode & (S_IXUSR | S_IXGRP | S_IXOTH) else 0o644
    flags: Final = os.O_WRONLY | os.O_CREAT | os.O_EXCL | (os.O_BINARY if os.name == "nt" else 0)
    # Creation applies the current umask without changing the process-wide setting.
    with src.open("rb") as source, os.fdopen(os.open(str(dest), flags, mode), "wb") as target:
        shutil.copyfileobj(source, target, length=1024 * 1024)

The fix establishes base permission defaults of 0o755 for executable source files and 0o644 for regular files. It then invokes os.open() with os.O_CREAT | os.O_EXCL, allowing the kernel's native file creation mechanism to apply the active process umask directly against these base permission modes.

In addition, enforcing os.O_EXCL prevents symlink redirection attacks during target environment creation. If a file or symlink already exists at the destination path, the file creation operation aborts instantly.

Exploitation Methodology

Exploitation requires multi-user context on a local system where virtual environments are created in shared or traversable directory locations, such as /tmp or shared project spaces.

An attacker identifies a target environment containing group- or world-writable files (such as /tmp/env/lib/python3.X/site-packages/pip/__init__.py). The attacker appends arbitrary Python code to the file.

When the victim executes pip or invokes Python within the target virtual environment, the modified module is imported and executed within the security context of the victim account.

Impact & Risk Analysis

Successful exploitation grants a local attacker code execution under the privileges of the target environment's owner. If the target user possesses higher privilege or access to sensitive credentials, the attacker can hijack those session rights.

Under CVSS v4.0 metrics, the vulnerability yields a base score of 4.4 (CVSS:4.0/AV:L/AC:H/AT:P/PR:L/UI:P/VC:L/VI:H/VA:L/SC:N/SI:N/SA:N). Integrity impact on the vulnerable system is evaluated as High due to full modification rights over Python executable packages.

The attack vector is restricted to local system access, and attack complexity is classified as High because specific environment caching and filesystem permissions conditions must be satisfied prior to creation.

Remediation & Mitigation Guidance

The primary remediation strategy is upgrading virtualenv to version 21.14.9 or later, which enforces process umask evaluation during file creation.

To audit and remediate existing virtual environments created by vulnerable versions, administrators should scan for overly permissive files in active virtual environment paths.

# Identify world-writable files inside a target virtual environment
find /path/to/venv -type f -perm -0002 -exec ls -l {} +
 
# Correct permissions across an existing environment
find /path/to/venv -type d -exec chmod 755 {} +
find /path/to/venv -type f -exec chmod 644 {} +
find /path/to/venv/bin -type f -exec chmod 755 {} +

Official Patches

pypaPull Request #3425: Enforce system umask during app-data seeding
pypaRelease tag 21.14.9

Fix Analysis (1)

Technical Appendix

CVSS Score
4.4/ 10
CVSS:4.0/AV:L/AC:H/AT:P/PR:L/UI:P/VC:L/VI:H/VA:L/SC:N/SI:N/SA:N
EPSS Probability
0.10%
Top 100% most exploited

Affected Systems

virtualenv < 21.14.9

Affected Versions Detail

Product
Affected Versions
Fixed Version
virtualenv
pypa
< 21.14.921.14.9
AttributeDetail
Vulnerability IDCVE-2026-113720
CWE IDCWE-732 (Incorrect Permission Assignment for Critical Resource)
CVSS v4.0 Score4.4 (Medium)
CVSS VectorCVSS:4.0/AV:L/AC:H/AT:P/PR:L/UI:P/VC:L/VI:H/VA:L/SC:N/SI:N/SA:N
Attack VectorLocal
Exploit StatusNo public weaponized exploit available
CISA KEV StatusNot listed
Patched Version21.14.9

MITRE ATT&CK Mapping

T1222File and Directory Permissions Modification
Defense Evasion
CWE-732
Incorrect Permission Assignment for Critical Resource

The software specifies permissions for a security-critical resource in a way that allows unintended access to that resource.

Vulnerability Timeline

Fix commit 35f0b33562790176dd186d0a3c517af3acc7a0e1 committed in PR #3425
2026-10-17
virtualenv version 21.14.9 published to PyPI
2026-10-20
GitHub Security Advisory GHSA-fc2g-4w5p-6whm published
2026-10-20
CVE-2026-113720 published
2026-10-20

References & Sources

  • [1]GitHub Security Advisory GHSA-fc2g-4w5p-6whm
  • [2]NIST NVD CVE-2026-113720 Detail
  • [3]CVE.org CVE-2026-113720 Record
  • [4]virtualenv Pull Request #3425
  • [5]virtualenv Commit 35f0b33562790176dd186d0a3c517af3acc7a0e1
  • [6]virtualenv Release 21.14.9

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•about 1 hour ago•CVE-2026-113723
7.1

CVE-2026-113723: OS Command Injection via Unsafe Prompt Expansion in PyPA virtualenv

A command injection vulnerability in PyPA virtualenv prior to version 21.14.9 allows local attackers to execute arbitrary commands when a user sources a generated shell activation script containing a crafted prompt value.

Alon Barad
Alon Barad
1 views•5 min read
•about 3 hours ago•CVE-2026-113718
7.1

CVE-2026-113718: Code Injection in pypa/virtualenv XonshActivator via Multibyte Encoding Misalignment

A code injection vulnerability in pypa/virtualenv prior to version 21.14.9 allows arbitrary command execution in xonsh shells using legacy multibyte encodings when sourcing activate.xsh.

Amit Schendel
Amit Schendel
6 views•5 min read
•about 4 hours ago•CVE-2026-113714
2.3

CVE-2026-113714: Cache Poisoning and Unvalidated Wheel Download in virtualenv

Prior to version 21.14.9, virtualenv downloads wheel files directly into its reusable persistent cache directory prior to verifying PyPI digests or compatibility. Combined with unsanitized stdout parsing from pip, a controlled package index can cause virtualenv to calculate digests against pre-existing local files while leaving unverified archives in the shared persistent cache.

Amit Schendel
Amit Schendel
5 views•5 min read
•about 5 hours ago•CVE-2026-113717
2.3

CVE-2026-113717: Package Digest Verification Bypass in virtualenv Pip Seeder

A verification bypass vulnerability in virtualenv allows unverified Python wheel installation when using pip seeding with the download flag. Affected versions fail to perform SHA-256 digest validation against PyPI metadata before invoking pip.

Alon Barad
Alon Barad
6 views•5 min read
•about 6 hours ago•CVE-2026-113713
4.4

CVE-2026-113713: Insecure Temporary File Symlink Handling in PyPA virtualenv

Insecure temporary file usage (CWE-377) in virtualenv app-data seeder creates dangling symlinks pointing to deleted temporary directories, allowing local attackers on shared systems to execute arbitrary code.

Amit Schendel
Amit Schendel
5 views•4 min read
•about 7 hours ago•CVE-2026-112937
6.1

CVE-2026-112937: Arbitrary Directory Deletion via TOCTOU Race Condition in filelock ReadWriteLock

A Time-of-Check Time-of-Use (TOCTOU) race condition in the Python `filelock` library (versions 4.1.0 to 4.2.0) allows local unprivileged attackers to cause arbitrary directory deletion by swapping file system targets during lock cleanup or dead owner sweeps.

Alon Barad
Alon Barad
7 views•5 min read