CVE-2026-113716
virtualenv: Builtin creation follows linked environment directories
virtualenv is a tool for creating isolated virtual python environments. Prior to 21.14.9, the builtin creator calls ensure_dir() for executable, library, and package directories, and ensure_dir() accepts an existing symlink to a directory because exists() follows it. Interpreter creation, seed installation, and activation generation then write through the linked parent outside the requested destination when another local account prepared the tree and the invoking user can access the target. The --clear option removes the planted tree first, while ordinary creation reaches it; arbitrary attacker-selected output bytes are not established. This issue is fixed in version 21.14.9.
Attack profile
How easy it is to exploit
- Attack vector
- Local
- Complexity
- High
- Privileges needed
- Low
- User interaction
- None
What an attacker can affect
- Confidentiality
- Low
- Integrity
- Low
- Availability
- Low
Exploit likelihood
What each source reports
CVE List Score used
4.5
virtualenv: Builtin creation follows linked environment directories
virtualenv is a tool for creating isolated virtual python environments. Prior to 21.14.9, the builtin creator calls ensure_dir() for executable, library, and package directories, and ensure_dir() accepts an existing symlink to a directory because exists() follows it. Interpreter creation, seed installation, and activation generation then write through the linked parent outside the requested destination when another local account prepared the tree and the invoking user can access the target. The --clear option removes the planted tree first, while ordinary creation reaches it; arbitrary attacker-selected output bytes are not established. This issue is fixed in version 21.14.9.
- Record
CVE-2026-113716- CVSS 3.1
- 4.5 Medium
CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:L - Weakness
- CWE-59
- Updated
- 2026-11-02
EUVDEUVD-2026-105297
4.5
virtualenv is a tool for creating isolated virtual python environments. Prior to 21.14.9, the builtin creator calls ensure_dir() for executable, library, and package directories, and ensure_dir() accepts an existing symlink to a directory because exists() follows it. Interpreter creation, seed installation, and activation generation then write through the linked parent outside the requested destination when another local account prepared the tree and the invoking user can access the target. The --clear option removes the planted tree first, while ordinary creation reaches it; arbitrary attacker-selected output bytes are not established. This issue is fixed in version 21.14.9.
- Record
EUVD-2026-105297- CVSS 3.1
- 4.5 Medium
CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:L - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-cw65-gx24-rc82
4.5
virtualenv: Builtin creation follows linked environment directories
Summary
The builtin creator accepts existing directory symlinks through ensure_dir() and writes environment files through those directories. This permits writes outside the requested destination.
Anthropic's OSS Scanner reported this as ANT-2026-MUFJEG11 in virtualenv-20261015-005, received on 15 October 2026.
Affected area
Directory preparation before environment files are created.
Attacker-controlled input
Another account must be able to prepare linked entries below the chosen destination before creation. The invoking user must have access to the linked destination. This does not require write access to the target itself under the other account.
Affected code
The relevant 21.14.8 source is in builtin creator, ensure_dir().
Mechanism
The builtin creator calls ensure_dir() for bin, lib, and package directories. ensure_dir() accepts an existing
symlink to a directory because exists() follows it. Interpreter creation, seed installation, and activation-script
generation then write through that parent link. A final-file check cannot prevent a write through a linked parent.
--clear removes the planted tree first; ordinary creation over a prepared destination reaches it.
Reproduction and evidence
The scanner's project tree contains venv/bin -> ../../.local/bin and a .pth file in the environment's package tree.
With the user's initially empty ~/.local/bin first on PATH, virtualenv venv exited successfully and wrote
python*, pip*, and activate* into ~/.local/bin. The marker was absent immediately after creation; a later
pip --version on the user's PATH loaded the seeded environment and the planted .pth code wrote the marker. A
second case began with the bin link resolving inside the environment; replacement of a planted package link during
seeding changed where it resolved, and writes again reached ~/.local/bin.
The attacker must prepare entries in an existing destination. The .pth content is already attacker-controlled and
would run if the user used that environment directly; the added effect is creation-time writing or replacement outside
the requested tree and an executable on the user's PATH pointing at it. The scanner traces this default builtin path
to 20.0.0b1. PR #3429 replaces linked directory components before
creation. Concurrent parent replacement remains a separate case.
Attack sequence
sequenceDiagram
participant A as Prepared destination
participant V as Builtin creator
participant L as venv/bin symlink
participant H as ~/.local/bin
participant U as User
A->>L: point to ../../.local/bin
V->>L: ensure_dir accepts existing directory link
V->>H: write python, pip and activate files through link
V-->>U: creation reports success
U->>H: run pip found on PATH
H->>A: interpreter loads planted .pth
A-->>U: marker created
Reproducer files
The following files are from the scanner report for ANT-2026-MUFJEG11. They were tested against commit a857a7823c73
in the scanner image. The repro entrypoint expects companion files under /tmp/repro.d; cases that change user IDs
need a disposable root-capable container. The last output line is BUG when the reported behavior occurs. These files
are included as evidence and were not rerun for this advisory update.
repro
#!/usr/bin/env python3
import os
import shutil
import subprocess
import sys
from pathlib import Path
WORK = Path("/tmp/planted-bin-link")
shutil.rmtree(WORK, ignore_errors=True)
def user_creates_venv_in_checkout_then_runs_pip(home, make_checkout):
local_bin = home / ".local/bin"
…
- Record
GHSA-cw65-gx24-rc82- CVSS 3.1
- 4.5 Medium
CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:L - Weakness
- CWE-59
- Updated
- 2026-11-02
NVD
4.5
virtualenv is a tool for creating isolated virtual python environments. Prior to 21.14.9, the builtin creator calls ensure_dir() for executable, library, and package directories, and ensure_dir() accepts an existing symlink to a directory because exists() follows it. Interpreter creation, seed installation, and activation generation then write through the linked parent outside the requested destination when another local account prepared the tree and the invoking user can access the target. The --clear option removes the planted tree first, while ordinary creation reaches it; arbitrary attacker-selected output bytes are not established. This issue is fixed in version 21.14.9.
- Record
CVE-2026-113716- CVSS 3.1
- 4.5 Medium
CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:L - Weakness
- CWE-59
- Updated
- 2026-11-02
OSV
4.5
virtualenv: Builtin creation follows linked environment directories
virtualenv is a tool for creating isolated virtual python environments. Prior to 21.14.9, the builtin creator calls ensure_dir() for executable, library, and package directories, and ensure_dir() accepts an existing symlink to a directory because exists() follows it. Interpreter creation, seed installation, and activation generation then write through the linked parent outside the requested destination when another local account prepared the tree and the invoking user can access the target. The --clear option removes the planted tree first, while ordinary creation reaches it; arbitrary attacker-selected output bytes are not established. This issue is fixed in version 21.14.9.
- Record
CVE-2026-113716- CVSS 3.1
- 4.5 Medium
CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:L - Weakness
- CWE-59
- Updated
- 2026-11-02
OSVDEBIAN-CVE-2026-113716
4.5
virtualenv is a tool for creating isolated virtual python environments. Prior to 21.14.9, the builtin creator calls ensure_dir() for executable, library, and package directories, and ensure_dir() accepts an existing symlink to a directory because exists() follows it. Interpreter creation, seed installation, and activation generation then write through the linked parent outside the requested destination when another local account prepared the tree and the invoking user can access the target. The --clear option removes the planted tree first, while ordinary creation reaches it; arbitrary attacker-selected output bytes are not established. This issue is fixed in version 21.14.9.
- Record
DEBIAN-CVE-2026-113716- CVSS 3.1
- 4.5 Medium
CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:L - Updated
- 2026-11-02
Show 6 moreShow less
OSVGHSA-cw65-gx24-rc82
4.5
virtualenv: Builtin creation follows linked environment directories
Summary
The builtin creator accepts existing directory symlinks through ensure_dir() and writes environment files through those directories. This permits writes outside the requested destination.
Anthropic's OSS Scanner reported this as ANT-2026-MUFJEG11 in virtualenv-20261015-005, received on 15 October 2026.
Affected area
Directory preparation before environment files are created.
Attacker-controlled input
Another account must be able to prepare linked entries below the chosen destination before creation. The invoking user must have access to the linked destination. This does not require write access to the target itself under the other account.
Affected code
The relevant 21.14.8 source is in builtin creator, ensure_dir().
Mechanism
The builtin creator calls ensure_dir() for bin, lib, and package directories. ensure_dir() accepts an existing
symlink to a directory because exists() follows it. Interpreter creation, seed installation, and activation-script
generation then write through that parent link. A final-file check cannot prevent a write through a linked parent.
--clear removes the planted tree first; ordinary creation over a prepared destination reaches it.
Reproduction and evidence
The scanner's project tree contains venv/bin -> ../../.local/bin and a .pth file in the environment's package tree.
With the user's initially empty ~/.local/bin first on PATH, virtualenv venv exited successfully and wrote
python*, pip*, and activate* into ~/.local/bin. The marker was absent immediately after creation; a later
pip --version on the user's PATH loaded the seeded environment and the planted .pth code wrote the marker. A
second case began with the bin link resolving inside the environment; replacement of a planted package link during
seeding changed where it resolved, and writes again reached ~/.local/bin.
The attacker must prepare entries in an existing destination. The .pth content is already attacker-controlled and
would run if the user used that environment directly; the added effect is creation-time writing or replacement outside
the requested tree and an executable on the user's PATH pointing at it. The scanner traces this default builtin path
to 20.0.0b1. PR #3429 replaces linked directory components before
creation. Concurrent parent replacement remains a separate case.
Attack sequence
sequenceDiagram
participant A as Prepared destination
participant V as Builtin creator
participant L as venv/bin symlink
participant H as ~/.local/bin
participant U as User
A->>L: point to ../../.local/bin
V->>L: ensure_dir accepts existing directory link
V->>H: write python, pip and activate files through link
V-->>U: creation reports success
U->>H: run pip found on PATH
H->>A: interpreter loads planted .pth
A-->>U: marker created
Reproducer files
The following files are from the scanner report for ANT-2026-MUFJEG11. They were tested against commit a857a7823c73
in the scanner image. The repro entrypoint expects companion files under /tmp/repro.d; cases that change user IDs
need a disposable root-capable container. The last output line is BUG when the reported behavior occurs. These files
are included as evidence and were not rerun for this advisory update.
repro
#!/usr/bin/env python3
import os
import shutil
import subprocess
import sys
from pathlib import Path
WORK = Path("/tmp/planted-bin-link")
shutil.rmtree(WORK, ignore_errors=True)
def user_creates_venv_in_checkout_then_runs_pip(home, make_checkout):
local_bin = home / ".local/bin"
…
- Record
GHSA-cw65-gx24-rc82- CVSS 3.1
- 4.5 Medium
CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:L - Weakness
- CWE-59
- Updated
- 2026-11-02
OSVUBUNTU-CVE-2026-113716
4.5
virtualenv is a tool for creating isolated virtual python environments. Prior to 21.14.9, the builtin creator calls ensure_dir() for executable, library, and package directories, and ensure_dir() accepts an existing symlink to a directory because exists() follows it. Interpreter creation, seed installation, and activation generation then write through the linked parent outside the requested destination when another local account prepared the tree and the invoking user can access the target. The --clear option removes the planted tree first, while ordinary creation reaches it; arbitrary attacker-selected output bytes are not established. This issue is fixed in version 21.14.9.
- Record
UBUNTU-CVE-2026-113716- CVSS 3.1
- 4.5 Medium
CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:L - Updated
- 2026-11-02
OSVAZL-110094 No score
CVE-2026-113716 affecting package python-virtualenv for versions less than 20.36.1-10
virtualenv is a tool for creating isolated virtual python environments. Prior to 21.14.9, the builtin creator calls ensure_dir() for executable, library, and package directories, and ensure_dir() accepts an existing symlink to a directory because exists() follows it. Interpreter creation, seed installation, and activation generation then write through the linked parent outside the requested destination when another local account prepared the tree and the invoking user can access the target. The --clear option removes the planted tree first, while ordinary creation reaches it; arbitrary attacker-selected output bytes are not established. This issue is fixed in version 21.14.9.
- Record
AZL-110094- Updated
- 2026-11-07
OSVBIT-virtualenv-2026-113716 No score
virtualenv: Builtin creation follows linked environment directories
virtualenv is a tool for creating isolated virtual python environments. Prior to 21.14.9, the builtin creator calls ensure_dir() for executable, library, and package directories, and ensure_dir() accepts an existing symlink to a directory because exists() follows it. Interpreter creation, seed installation, and activation generation then write through the linked parent outside the requested destination when another local account prepared the tree and the invoking user can access the target. The --clear option removes the planted tree first, while ordinary creation reaches it; arbitrary attacker-selected output bytes are not established. This issue is fixed in version 21.14.9.
- Record
BIT-virtualenv-2026-113716- Updated
- 2026-11-02
OSVCLSA-2026-1793107254 No score
TuxCare security update for virtualenv (8 CVEs)
TuxCare rebuilt virtualenv to address 8 CVEs. Fixed in 20.39.1.post5+tuxcare.
- Record
CLSA-2026-1793107254- Updated
- 2026-11-02
OSVopenSUSE-SU-2026:12372-1 No score
python313-virtualenv-21.15.1-1.1 on GA media
These are all security issues fixed in the python313-virtualenv-21.15.1-1.1 package on the GA media of openSUSE Tumbleweed.
- Record
openSUSE-SU-2026:12372-1- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
virtualenvPyPI |
before 21.14.9 | 21.14.9 |
python-virtualenvAzure Linux:3 |
before 20.36.1-10 | 20.36.1-10 |
virtualenvBitnami |
before 21.14.9 | 21.14.9 |
virtualenvTuxCare:PyPI From an advisory covering 8 CVEs |
20.39.1 up to 20.39.1.post5+tuxcare, plus listed versions 20.39.1.post1+tuxcare20.39.1.post2+tuxcare20.39.1.post3+tuxcare20.39.1.post4+tuxcare |
20.39.1.post5+tuxcare |
python-virtualenvDebian:12 |
All versions, plus listed versions 20.17.1+ds-120.19.0+ds-120.21.0+ds-120.23.0+ds-120.23.0+ds-2 Show 28 moreShow less20.24.1+ds-120.24.6+ds-120.24.6+ds-220.25.0+ds-120.25.0+ds-220.25.1+ds-120.26.1+ds-120.26.2+ds-120.26.6+ds-120.27.0+ds-120.28.0+ds-120.29.1+ds-120.29.3+ds-120.30.0+ds-120.30.0+ds-220.30.0+ds-320.31.2+ds-120.33.1+ds-120.34.0+ds-120.35.3+ds-120.35.4+ds-120.36.1+ds-120.38.0+ds-121.2.0+ds-121.2.4+ds-121.3.1+ds-121.4.1+ds-121.5.1+ds-1 |
None known |
python-virtualenvDebian:13 |
All versions, plus listed versions 20.31.2+ds-120.31.2+ds-1+deb13u120.33.1+ds-120.34.0+ds-120.35.3+ds-1 Show 8 moreShow less20.35.4+ds-120.36.1+ds-120.38.0+ds-121.2.0+ds-121.2.4+ds-121.3.1+ds-121.4.1+ds-121.5.1+ds-1 |
None known |
python-virtualenvDebian:14 |
All versions, plus listed versions 20.31.2+ds-120.33.1+ds-120.34.0+ds-120.35.3+ds-120.35.4+ds-1 Show 7 moreShow less20.36.1+ds-120.38.0+ds-121.2.0+ds-121.2.4+ds-121.3.1+ds-121.4.1+ds-121.5.1+ds-1 |
None known |
virtualenvPyPI |
before 21.14.9, plus listed versions 0.80.8.10.8.20.8.30.8.4 Show 45 moreShow less0.90.9.10.9.21.01.11.101.10.11.111.11.11.11.21.11.31.11.41.11.51.11.61.21.31.3.11.3.21.3.31.3.41.41.4.11.4.21.4.31.4.41.4.51.4.61.4.71.4.81.4.91.4rc11.51.5.11.5.21.61.6.11.6.21.6.31.6.41.71.7.11.7.1.11.7.1.21.7.21.8 |
21.14.9 |
python-virtualenvUbuntu:14.04:LTS |
All versions, plus listed versions 1.10.1-11.11-11.11-21.11.4-11.11.4-1ubuntu1 |
None known |
python-virtualenvUbuntu:16.04:LTS |
All versions, plus listed versions 1.11.6+ds-114.0.5+ds-114.0.5+ds-214.0.5+ds-415.0.0+ds-1 Show 6 moreShow less15.0.0+ds-215.0.1+ds-115.0.1+ds-215.0.1+ds-315.0.1+ds-3ubuntu115.0.1+ds-3ubuntu1.1 |
None known |
Show 7 moreShow less
| Package | Affected | Fixed |
|---|---|---|
python-virtualenvUbuntu:18.04:LTS |
All versions, plus listed versions 15.1.0+ds-115.1.0+ds-1.1 |
None known |
python-virtualenvUbuntu:Pro:20.04:LTS |
All versions, plus listed versions 15.1.0+ds-215.1.0+ds-2build115.1.0+ds-2ubuntu120.0.13-120.0.17-120.0.17-1ubuntu0.320.0.17-1ubuntu0.420.0.17-1ubuntu0.4+esm1 |
None known |
python-virtualenvUbuntu:Pro:22.04:LTS |
All versions, plus listed versions 20.4.6+ds-220.10.0+ds-120.12.1+ds-120.13.0+ds-120.13.0+ds-220.13.0+ds-2ubuntu0.1~esm1 |
None known |
python-virtualenvUbuntu:Pro:24.04:LTS |
All versions, plus listed versions 20.24.1+ds-120.24.6+ds-120.24.6+ds-220.25.0+ds-120.25.0+ds-220.25.0+ds-2ubuntu0.1~esm1 |
None known |
python-virtualenvUbuntu:26.10 |
All versions, plus listed versions 20.36.1+ds-121.4.1+ds-121.5.1+ds-1 |
None known |
python-virtualenvUbuntu:26.04:LTS |
All versions, plus listed versions 20.31.2+ds-120.35.3+ds-120.35.4+ds-120.36.1+ds-1 |
None known |
python-virtualenvopenSUSE:Tumbleweed From an advisory covering 9 CVEs |
before 21.15.1-1.1 | 21.15.1-1.1 |
History
| Recorded | Changed | Sources |
|---|---|---|
| affected | OSV | |
| affected | ||
| facts | OSV | |
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-113716 is a medium vulnerability (CVSS 4.5) in Pypa Virtualenv, published October 20, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.14%, the 3rd percentile. Fixed in virtualenv 21.14.9.
References
github.com/pypa/virtualenv/security/advisories/GHSA-cw65-gx24-rc82
github.com/pypa/virtualenv/pull/3429
github.com/pypa/virtualenv/commit/554d9f9d4f7758f5cf53f993031e29787f1f74c5
github.com/pypa/virtualenv/releases/tag/21.14.9
nvd.nist.gov/vuln/detail/CVE-2026-113716
github.com/advisories/GHSA-cw65-gx24-rc82
Show 14 moreShow less
github.com/CVEProject/cvelistV5/tree/main/cves/2026/113xxx/CVE-2026-113716.json
security-tracker.debian.org/tracker/CVE-2026-113716
github.com/pypa/virtualenv
ubuntu.com/security/CVE-2026-113716
cve.org/CVERecord?id=CVE-2026-113716
suse.com/security/cve/CVE-2026-113714
suse.com/security/cve/CVE-2026-113716
suse.com/security/cve/CVE-2026-113718
suse.com/security/cve/CVE-2026-113720
suse.com/security/cve/CVE-2026-113722
suse.com/security/cve/CVE-2026-113724
suse.com/security/cve/CVE-2026-113726
suse.com/security/cve/CVE-2026-113732
suse.com/security/cve/CVE-2026-115586
Left out here: 254 versions and the rest of 2 source descriptions. The JSON record has them.