Attack ChainAIDerived
Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain
-
AccessObtain local co-tenant account on host
-
ExploitPre-plant dangling symlink inside destination
-
ExecutionVictim runs virtualenv environment creation
-
ImpactConstrained content written to external file
Vulnerability Assessment
| Weakness |
CWE
OWASP Top 10:2025
A01:2025 - Broken Access Control
ASVS 5.0
V5 - File Handling Symlink resolution safety
|
| Exploitation Conditions | Requires a SECOND, separate local user account on the same host (per the description: 'another local account that prepares final entries inside the destination'). That account must pre-create a dangling symbolic link or extra hard link at specific generated paths inside the virtualenv destination - e.g. pyvenv.cfg, activation scripts produced by ViaTemplateActivator, .gitignore, the CACHEDIR.TAG, import-hook .pth files, or bin/ interpreter files - before the legitimate user triggers environment creation. LIMITING FACTORS: the destination parent directory must remain controlled by the environment owner during creation (an attacker who can replace the parent is explicitly out of scope); exploitation is local-only with no network vector; it depends on timing against the victim's virtualenv run (hence AC:H); and the written content is constrained to virtualenv-generated text under the invoking user's permissions, so it is not arbitrary attacker-controlled data. It does NOT apply to ordinary single-user developer machines where no untrusted local account can write into the destination. |
| Impact | This is a genuinely low-to-moderate-priority local privilege/integrity issue, not an internet-facing emergency. The CVSS 3.1 vector (AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:L = 4.5 MEDIUM) is internally consistent with the description: exploitation requires an attacker who already holds a separate local account on the same host (PR:L), and high attack complexity (AC:H) because the attacker must pre-position a dangling symbolic or hard link inside the victim's destination and have the victim then run environment creation, all while the destination parent remains owned by the victim. No EPSS score, KEV entry, SSVC decision, or POC was provided in the input; per the data this is 'no public exploit identified at time of analysis.' All three impact sub-scores are only Low, and the attack is confined to a multi-user host where an untrusted local account can write into the target tree - an uncommon deployment for virtualenv. CONFLICT TO VERIFY: the input Tags label this 'Information Disclosure,' but the description and the CWE-59 (link following) fix describe creating/overwriting files OUTSIDE the requested tree with attacker-chosen paths - an integrity/file-write problem, not confidentiality loss; the 'Information Disclosure' categorization appears mislabeled. Net: real but niche, prioritize on shared/multi-tenant build hosts and CI runners, deprioritize on single-user developer machines. |
| Exploit ScenarioDerived | On a shared Linux build host, a low-privileged local attacker pre-creates a dangling symlink (or hard link) at a path such as pyvenv.cfg or an activation script name inside a directory where a higher-value user is about to create a virtualenv. When that user runs virtualenv, ViaTemplateActivator._generate() and PyEnvCfg.write() follow the planted link instead of replacing it, so virtualenv-generated content is written to an attacker-chosen location outside the intended environment using the victim's permissions. No public exploit code was identified in the provided intelligence. |
Get an e-mail when this CVE is exploited, patched or re-scored. Free account.
Alert meAnalysisAIv1 – Oct 20, 2026
Symlink-following file writes in virtualenv before 21.14.9 let a second, unprivileged local account redirect generated environment files outside the requested tree (CWE-59). When the destination contains a pre-planted dangling symlink or an extra hard link at paths such as pyvenv.cfg, activation scripts, .gitignore, CACHEDIR.TAG, import-hook .pth files, or bin/ interpreter files, virtualenv creation writes constrained generated text through the link with the invoking user's permissions, producing limited integrity and availability impact outside the environment. Exploitation requires local access, a separate hostile account able to write into the destination, and timing against the victim's creation run (CVSS 3.1 AV:L/AC:H/PR:L, base 4.5); no public exploit was identified at time of analysis and the issue is not in CISA KEV. Affected users should upgrade to 21.14.9.
RemediationAI
Vendor-released patch: upgrade to virtualenv 21.14.9, which routes all generated writes through an exclusive-create write_file() helper and adds link removal plus an ensure_within() containment check for the stdlib venv creator (see https://github.com/pypa/virtualenv/releases/tag/21.14.9 and advisory GHSA-558c-9hv2-4prj). If immediate upgrade is not possible, the most effective compensating control is to never create environments in locations writable by other local accounts: use a destination whose parent and the destination itself are mode 0700 and owned by the invoking user, avoiding shared temp or group-writable build directories - this directly defeats the prerequisite (a second account planting links in the destination) but does nothing for environments already created in shared paths, which should be deleted and recreated after upgrade. Operators of CI or multi-tenant hosts can also pre-scan the destination for dangling symlinks and st_nlink > 1 files (pyvenv.cfg, .gitignore, .pth files, activation scripts, bin/) and abort creation if any are found; this is a detection-only measure with a small race window. None of these workarounds remove the vulnerable code, so upgrading 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
virtualenv builds a Python environment by writing a set of generated text artifacts: pyvenv.cfg via PyEnvCfg.write(), shell/PowerShell activation scripts via ViaTemplateActivator._generate(), .gitignore and CACHEDIR.TAG in Creator, import-hook .pth files in the via_global_ref creator, and pip seed launcher scripts. The original code guarded those writes with Path.exists() followed by Path.unlink(); because Path.exists() follows the link and returns False for a dangling symlink, the unlink was skipped and the subsequent write_bytes()/write_text() followed the surviving link to an attacker-chosen target. Separately, PyEnvCfg.write() opened pyvenv.cfg without replacing an existing symbolic or hard link, so a hard link planted at that path received the generated configuration. Successful exploitation yields only constrained virtualenv-generated content (not arbitrary attacker data) written with the victim's privileges, which is why impact is capped at C:L/I:L/A:L in the assessed vector (CVSS 4.5, AV:L/AC:H/PR:L/UI:N). The upstream fix (PR #3431, commit d25f28699eefb1fc34a251e5adf2b5de844c36cd) introduces a write_file() helper in virtualenv.util.path that creates generated text files exclusively so a replacement link cannot redirect the final open, funnels all the affected write sites through it, and adds an ensure_within() containment check plus explicit removal of symlinks/junctions and hard-linked files before the stdlib venv creator writes interpreter files. Exploitation is explicitly out of scope where an attacker can replace the destination parent directory; the parent must remain owner-controlled during creation.
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
A separate local account must plant a link and win timing against the victim's run (AV:L/AC:H/PR:L); only virtualenv-generated content is written outside the tree, giving I:L/A:L with no real disclosure (C:N).
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, ViaTemplateActivator._generate() removes an existing output only when Path.exists() is true, allowing a dangling symlink to survive and redirect generated activation content, while PyEnvCfg.write() opens pyvenv.cfg without first replacing an existing symbolic or hard link. Another local account that prepares final entries inside the destination can therefore cause environment creation to create or overwrite files outside the requested tree with constrained virtualenv-generated content and the invoking user's permissions. The destination parent must remain controlled by the environment owner during creation; concurrent parent-directory replacement is a separate concern. 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
Path traversal in PyPA virtualenv's seed-package cleanup lets a local, low-privileged attacker delete files outside the
EUVD-2026-105303
GHSA-558c-9hv2-4prj
NVD
CVE.org
EPSS
Exploit-DB