Skip to main content

virtualenv EUVDEUVD-2026-105303

| CVE-2026-113721 MEDIUM
Improper Link Resolution Before File Access (CWE-59)
2026-10-20 GitHub_M GHSA-558c-9hv2-4prj
4.5
CVSS 3.1 · Vendor: GitHub_M
View

Attack ChainAIDerived

Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain

  1. Access
    Obtain local co-tenant account on host
  2. Exploit
    Pre-plant dangling symlink inside destination
  3. Execution
    Victim runs virtualenv environment creation
  4. Impact
    Constrained 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.

This Month Plan within 30 days. Why: MEDIUM severity (CVSS 4.0-6.9).
Patch available 0.1% exploitation probability (EPSS)

Get an e-mail when this CVE is exploited, patched or re-scored. Free account.

Alert me

AnalysisAIv1 – 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

virtualenv < 21.14.9

Affected Packages

pypi virtualenv fix: 21.14.9

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

Vendor (GitHub_M) PRIMARY 4.5 MEDIUM
AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:L
vuln.today AI 3.6 LOW

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).

3.1 AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:L
4.0 AV:L/AC:L/AT:P/PR:L/UI:N/VC:N/VI:L/VA:L/SC:N/SI:N/SA:N
Red Hat 4.5 MEDIUM

Primary rating from Vendor (GitHub_M).

CVSS VectorVendor: GitHub_M

Attack Vector
Local
Attack Complexity
High
Privileges Required
Low
User Interaction
None
Scope
Unchanged
Confidentiality
Low
Integrity
Low
Availability
Low

Lifecycle Timeline

2
Patch available
Oct 20, 2026 - 21:18 EUVD
CVE Published
Oct 20, 2026 - 19:46 cve.org
MEDIUM 4.5

DescriptionCVE.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

EPSS Score
0.1%
Top 98% exploitable
Prevalence
High
virtualenv is a near-standard Python tooling package across development and CI environments
Threat Intel
1
1 source
Data Quality
6 sources
Confidence: High

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.

SignalValue
Severity MEDIUM
CISA KEV No
Public POC No
EPSS 0.1%
Patch available Yes
Active threat No
Deciding rule
MEDIUM severity (CVSS 4.0-6.9)
What every action level means
Emergency Immediate action required. Criteria: CRITICAL + in CISA KEV (actively exploited) without patch, OR CRITICAL + EPSS > 30% without patch, OR CRITICAL + active threat signals without patch.
Act Now Prioritize within 24-48h. Criteria: in KEV with patch available, OR CRITICAL + public POC, OR HIGH + EPSS > 10%, OR CRITICAL + active threat, OR any CRITICAL severity.
This Week Schedule remediation this week. Criteria: HIGH severity (CVSS 7.0-8.9). Patch within normal change window.
This Month Plan within 30 days. Criteria: MEDIUM severity (CVSS 4.0-6.9), lower exploitation probability. Include in regular patch cycle.
Monitor Track and reassess. Criteria: LOW severity (CVSS 0.1-3.9), minimal exploitation risk. No immediate action needed.

SSVC AssessmentENISA

SSVC Decision· derived
Scheduled
Exploitation· derived
None
System Exposure· derived
Small
Automatable· derived
No
Human Impact· derived
High

Priority Score

22
Low Medium High Critical
KEV: 0
EPSS: 0
CVSS: +22
PoC: 0
Weaponized: 0
Threat intel: 0
Gov advisory: 0

Attack Technique

Information disclosure occurs when an application unintentionally exposes sensitive data that aids attackers in reconnaissance or directly compromises security.

CVE-2024-53899 HIGH POC
7.8 Nov 24

virtualenv before 20.26.6 allows command injection through the activation scripts for a virtual environment. Rated high

CVE-2026-102930 HIGH POC
7.7 Sep 29

virtualenv versions prior to 21.7.12 cache and seed pip/setuptools wheels without verifying their bytes, so an attacker

CVE-2026-102938 MEDIUM POC
5.8 Sep 29

Configuration injection in PyPA virtualenv before 21.7.11 lets a line boundary embedded in a prompt value inject extra k

CVE-2026-113722 HIGH
7.8 Oct 20

Command injection in PyPA virtualenv before 21.14.9 lets an attacker who controls the destination path of a virtual envi

CVE-2026-113725 HIGH
7.8 Oct 20

Command injection in virtualenv's bash activation script prior to 21.14.7 allows a crafted environment name or --prompt

CVE-2026-102925 HIGH
7.8 Sep 29

Command injection in the bash, zsh, and fish activation scripts generated by virtualenv releases prior to 21.7.13 lets a

CVE-2026-102937 HIGH
7.3 Sep 29

Command injection in PyPA virtualenv before 21.7.12 allows an attacker who controls the environment's prompt value - via

CVE-2026-115586 HIGH
7.1 Oct 23

Command injection in virtualenv's bash activator lets an attacker-supplied --prompt value be stored unescaped in PS1 and

CVE-2026-113723 HIGH
7.1 Oct 20

Caller-influenced prompt text in virtualenv's bash activation script prior to 21.14.9 can be re-expanded by bash as exec

CVE-2026-113718 HIGH
7.1 Oct 20

A code injection flaw in PyPA virtualenv before 21.14.9 lets attacker-influenced non-ASCII characters in the xonsh promp

CVE-2026-113724 MEDIUM
4.5 Oct 20

Symlink following in virtualenv's safe_delete() deletion-error handler (all versions prior to 21.14.9) lets a local atta

CVE-2026-113719 MEDIUM
4.5 Oct 20

Path traversal in PyPA virtualenv's seed-package cleanup lets a local, low-privileged attacker delete files outside the

Vendor StatusVendor

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy