Attack ChainAIDerived
Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain
-
AccessObtain local user account on shared host
-
DeliveryPlant directory symlink or junction at target venv path
-
ExploitVictim invokes ordinary virtualenv creation
-
ExecutionWrites traverse link outside intended destination
-
ImpactRead or corrupt redirected files
Vulnerability Assessment
| Weakness |
CWE
OWASP Top 10:2025
A01:2025 - Broken Access Control
ASVS 5.0
V5 - File Handling Symlink resolution safety
|
| Exploitation Conditions | Exploitation requires a SECOND local account to have already created a directory symlink or Windows junction at one of the environment's executable, library, or package directory paths inside the requested destination, AND the invoking user must be able to access that pre-planted target. It only triggers during ordinary creation: the --clear option removes the planted tree before building and therefore prevents the issue, so vulnerable use is limited to default (non---clear) runs. Practical exploitation is further constrained by AC:H - the attacker must pre-position the link and satisfy access/timing conditions - and by PR:L, since a local account is needed; there is no remote or unauthenticated vector, and the write ceiling is bounded because arbitrary attacker-chosen content is not established. |
| Impact | This is a genuinely low-priority, locally-scoped issue rather than a high-impact remote flaw, and all available signals agree. The provided CVSS 3.1 vector (AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:L = 4.5, MEDIUM) describes a local attack requiring an already-authenticated low-privilege account, high complexity (a second local account must pre-position a malicious symlink/junction and win access/timing conditions), and only low confidentiality, integrity, and availability impact. The description explicitly caps the integrity ceiling by noting 'arbitrary attacker-selected output bytes are not established,' so this is not a clean arbitrary-write-to-root primitive. No EPSS score, no CISA KEV listing, and no public proof-of-concept were provided in the input; accordingly the exploitation status is: no public exploit identified at time of analysis. There are no conflicting signals - the CVSS local/high-complexity framing, the CWE-59 (link-following) classification, and the source diff (ensure_dir → ensure_within) are mutually consistent. The one caveat is scope of impact: while tagged 'Information Disclosure,' the mechanism is symlink-redirected writes through a linked parent, which is as much an integrity/path-traversal concern as a disclosure one, consistent with the balanced C:L/I:L/A:L scoring. |
| Exploit ScenarioDerived | On a shared multi-user host, a low-privileged attacker pre-creates a directory symlink (or Windows junction) at a path the victim's virtualenv will use for its executable, library, or package directory. When the victim later runs an ordinary (non---clear) virtualenv creation, interpreter setup, seed installation, and activation generation write through the attacker's link to a location outside the intended destination, allowing the attacker to observe or corrupt the redirected files. No public exploit code was identified, and high attack complexity (pre-positioning plus access/timing) limits practical abuse. |
Get an e-mail when this CVE is exploited, patched or re-scored. Free account.
Alert meAnalysisAIv1 – Oct 20, 2026
Symlink-following during environment creation in PyPA virtualenv versions prior to 21.14.9 allows a second local account to redirect writes into a pre-planted directory symlink (or Windows junction) so that interpreter creation, seed installation, and activation generation land outside the requested destination. Only the invoking user's own creation run is affected, the attacker must already control a local account and have planted the link where the executable, library, or package directory will be built, and arbitrary attacker-chosen bytes at the target are not established, which is why the assessed impact is limited (CVSS 4.5, AV:L/AC:H/PR:L). Default (non---clear) creation is the vulnerable path, since --clear wipes the planted tree first; no public exploit code was identified at time of analysis and the issue is not tied to confirmed active exploitation. Upgrade to 21.14.9 to close it.
RemediationAI
Vendor-released patch: upgrade virtualenv to 21.14.9 or later (pip install --upgrade virtualenv==21.14.9), see https://github.com/pypa/virtualenv/releases/tag/21.14.9 and the advisory at https://github.com/pypa/virtualenv/security/advisories/GHSA-cw65-gx24-rc82; the fix is also inspectable in PR #3429. If upgrading is not immediately possible, two concrete compensating controls apply. First, pass --clear when creating environments, which deletes the planted tree before building and therefore blocks the pre-positioned symlink path - trade-off: all existing contents of the destination directory, including any environment you wanted to reuse, are destroyed. Second, create environments only in destinations whose parent directories are owned by the invoking user and not writable by other local accounts (avoid shared, group-writable, or world-writable paths such as /tmp), and pre-create the destination directory yourself so no other account can plant a link inside it - trade-off: this does not protect destinations already shared with other trusted-but-distinct accounts and requires changing build/CI directory conventions. Neither workaround removes the underlying exists()-based check, so patching remains the only complete fix.
Affected VersionsENISA
Affected Packages
Source: OSV (Open Source Vulnerabilities)
Affects your stack
Affects 1 package in pypi
Checking this CVE against your own stacks and servers is part of the Basic plan and up.
Technical ContextAI · show details
The flaw is CWE-59 (link following) rooted in virtualenv's path helper: the builtin creator called ensure_dir() for the executable, library, and package directories, and ensure_dir() used exists(), which resolves symlinks, so an existing symlink-to-directory was accepted as a valid destination instead of being replaced. Subsequent seeding steps and activation-script generation then wrote through that link into the attacker-prepared parent. The fix (PR #3429, commit 554d9f9d) replaces ensure_dir() with ensure_within(), applied in via_global_self_do.py's create() and in venv.py's create(), where the bin_dir, purelib, and platlib paths are now all validated against the destination root before use. The new helper rejects parent-traversal components that would escape the environment, raises NotADirectoryError when a non-directory is encountered where a directory must be created, replaces pre-existing directory symlinks and Windows junctions (logging each replacement) even when they point inside the environment, and creates nested paths otherwise; unit tests cover symlink replacement, junction replacement on Windows, nested path creation, rejection of regular files, and rejection of escaping paths.
Know when Virtualenv gets its next vulnerability
- Watch products and get an email when something new is published
- Check this CVE against your own stack and servers
- Exploit and PoC references, threat intelligence from 22 sources
No credit card · 7-day full trial
Severity by source
AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:L
Local-only symlink attack (AV:L) needing a pre-planted link by another account under access/timing constraints (AC:H) and a local account (PR:L); redirected writes give bounded C/I/A low impact.
Primary rating from Vendor (GitHub_M).
CVSS VectorVendor: GitHub_M
Lifecycle Timeline
2DescriptionCVE.org
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.
Threat Intelligence Overview
How this decision was reached
The engine reads each signal below and applies a fixed list of rules from top to bottom. The first rule that matches sets the recommended action – like a statement, every line is shown.
What every action level means
SSVC AssessmentENISA
Priority Score
Attack Technique
Information disclosure occurs when an application unintentionally exposes sensitive data that aids attackers in reconnaissance or directly compromises security.
More in Virtualenv
View allvirtualenv before 20.26.6 allows command injection through the activation scripts for a virtual environment. Rated high
virtualenv versions prior to 21.7.12 cache and seed pip/setuptools wheels without verifying their bytes, so an attacker
Configuration injection in PyPA virtualenv before 21.7.11 lets a line boundary embedded in a prompt value inject extra k
Command injection in PyPA virtualenv before 21.14.9 lets an attacker who controls the destination path of a virtual envi
Command injection in virtualenv's bash activation script prior to 21.14.7 allows a crafted environment name or --prompt
Command injection in the bash, zsh, and fish activation scripts generated by virtualenv releases prior to 21.7.13 lets a
Command injection in PyPA virtualenv before 21.7.12 allows an attacker who controls the environment's prompt value - via
Command injection in virtualenv's bash activator lets an attacker-supplied --prompt value be stored unescaped in PS1 and
Caller-influenced prompt text in virtualenv's bash activation script prior to 21.14.9 can be re-expanded by bash as exec
A code injection flaw in PyPA virtualenv before 21.14.9 lets attacker-influenced non-ASCII characters in the xonsh promp
Symlink following in virtualenv's safe_delete() deletion-error handler (all versions prior to 21.14.9) lets a local atta
Symlink-following file writes in virtualenv before 21.14.9 let a second, unprivileged local account redirect generated e
EUVD-2026-105297
GHSA-cw65-gx24-rc82
NVD
CVE.org
EPSS
Exploit-DB