Attack ChainAIDerived
Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain
-
AccessControl prompt source outside trust boundary
-
DeliveryEmbed line boundary plus home= in prompt
-
Exploitvirtualenv writes injected pyvenv.cfg
-
ExecutionReader parses extra key, last-value-wins overrides home
-
PersistConsumer runs attacker-selected base interpreter
-
ImpactCode executes in victim environment
Vulnerability Assessment
| Weakness |
CWE
OWASP Top 10:2025
A05:2025 - Injection
ASVS 5.0
V1 - Encoding and Sanitization CRLF sequence sanitization
|
| Exploitation Conditions | Requires that the prompt value - supplied via the --prompt CLI flag, the VIRTUALENV_PROMPT environment variable, or virtualenv configuration input - originate from outside the operator's trust boundary (e.g. an automated venv-creation pipeline that derives the prompt from an untrusted project name, CI/CD variable, or shared config file). The attacker must be able to embed a character that str.splitlines() treats as a line boundary (\n, \r, \v, \f, \x1c-\x1e, \x85, U+2028, or U+2029) plus an injected key such as 'home'. Limiting factors: exploitation is local (AV:L), needs a virtualenv run (user interaction), and only affects trust when prompt input is externally influenced - a directly operator-supplied prompt merely corrupts the operator's own environment. Fixed configurations running virtualenv 21.7.11+ are not exploitable. |
| Impact | This is a genuine but conditional integrity flaw, not a high-severity emergency. The vendor CVSS 4.0 vector (5.8, AV:L/AC:L/AT:P/PR:N/UI:P) is internally consistent with the description: exploitation is local, requires a passive attack precondition (AT:P) and user interaction (UI:P - an operator running virtualenv), and the dominant impact is integrity (VI:H) because injecting a duplicate 'home' key steers consumers to an attacker-selected base interpreter. There is no EPSS score, no CISA KEV listing, and no public weaponized exploit - the PR adds an atheris fuzz harness and hypothesis property tests, which demonstrate the injection invariant but are defensive test tooling, not exploit code, so this is 'no public exploit identified at time of analysis.' The critical caveat, stated explicitly by the advisory, is that the security impact only materializes when prompt input crosses the operator's trust boundary (e.g. a prompt derived from an untrusted project name, CI variable, or shared config); a directly-typed prompt merely corrupts the operator's own environment and is self-inflicted. The 'Information Disclosure' tag conflicts with the actual VI:H/VC:L profile - the real risk is configuration injection leading to interpreter substitution (integrity/code-path control), not data leakage. Net: real priority for automated/multi-tenant virtualenv pipelines where prompts come from untrusted sources; low real risk for ordinary interactive developer use despite virtualenv's ubiquity. |
| Exploit ScenarioDerived | An automation system (e.g. CI or a hosting platform) creates virtual environments and derives the --prompt or VIRTUALENV_PROMPT value from attacker-controlled data such as a repository name or user-supplied config. The attacker embeds a line boundary (newline, carriage return, or a Unicode separator like U+2028) followed by 'home = /attacker/path' in that value, so virtualenv writes a pyvenv.cfg whose reader parses the injected line and, because the last duplicate key wins, overrides the real 'home' with an attacker-selected base interpreter. No public exploit code exists, and exploitation is local with required user interaction. |
Get an e-mail when this CVE is exploited, patched or re-scored. Free account.
Alert meAnalysisAIv1 – Sep 29, 2026
Configuration injection in PyPA virtualenv before 21.7.11 lets a line boundary embedded in a prompt value inject extra keys into the generated pyvenv.cfg, potentially overriding the 'home' key so a subsequent environment resolves to an attacker-chosen base interpreter. The flaw is conditional rather than remotely exploitable: it is assessed as local (AV:L) with user interaction (UI:R per the independent assessment, UI:P in the CVSS 4.0 vector) and only has security consequence when the prompt value originates outside the operator's trust boundary - for example an automated venv-creation pipeline or CI job that derives --prompt or VIRTUALENV_PROMPT from an untrusted project name or shared configuration; a prompt typed directly by the operator merely corrupts the operator's own environment. No public exploit code and no confirmed active exploitation were identified at time of analysis, and EPSS/KEV signals were not provided; version 21.7.11 fixes the issue, and the referenced upstream PR adds fuzz and property tests asserting the invariant that a written value can never be read back as extra configuration keys.
RemediationAI
Vendor-released patch: 21.7.11 - upgrade virtualenv to 21.7.11 or later (release notes at https://github.com/pypa/virtualenv/releases/tag/21.7.11, advisory at https://github.com/pypa/virtualenv/security/advisories/GHSA-9h9j-4vrj-gf7g, and the code change in https://github.com/pypa/virtualenv/pull/3247, which rewrites PyEnvCfg values through a _one_line() helper that collapses every str.splitlines() boundary to a space). If upgrading immediately is not possible, the most effective compensating control is to ensure no prompt value ever crosses a trust boundary: never pass an untrusted CI/CD variable, project name, repository slug, or shared config-file value into --prompt or VIRTUALENV_PROMPT, and instead pass a fixed literal prompt or omit the prompt entirely (the trade-off is losing the human-readable environment label, which is cosmetic). Where a derived prompt is unavoidable, sanitize it before use by stripping or rejecting the boundary characters \n, \r, \v, \f, \x1c, \x1d, \x1e, \x85, U+2028 and U+2029 - note this must be applied in every pipeline that invokes virtualenv, since a single unsanitized path reopens the issue. Restrict write access to any virtualenv configuration file or environment variable source read during environment creation, and treat pyvenv.cfg files created by automation as untrusted input before activating the environment: verify that the 'home' value points to the expected base interpreter path, since the duplicate-key last-value-wins parse means an injected home silently wins. These controls are detective or scoping measures, not substitutes for the 21.7.11 upgrade, and none of them prevent corruption when the operator themselves supplies the malicious prompt content through their own shell.
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
pyvenv.cfg is a line-oriented key/value format with no escape syntax, and virtualenv's PyEnvCfg.write() historically emitted each entry as '{key} = {value}' verbatim while PyEnvCfg._read_values() parsed the file back with str.splitlines(), applying last-value-wins semantics for duplicate keys. Because Python's str.splitlines() recognizes more boundaries than just LF and CR - including \v, \f, \x1c, \x1d, \x1e, \x85 (NEL), U+2028 (line separator) and U+2029 (paragraph separator) - any of those characters surviving into the prompt value started a new configuration line on write, and the reader then accepted the injected lines as legitimate keys. The root-cause class is CWE-93, improper neutralization of CRLF (here, generalized line-boundary) sequences in generated structured data. The upstream fix in PR #3247 introduces an explicit _LINE_BOUNDARIES tuple matching exactly the boundaries splitlines() honors and a _one_line() helper that collapses each boundary to a space before writing both keys and values, so a value can never round-trip into additional configuration lines. The same PR adds a coverage-guided Atheris fuzz harness (tasks/fuzz_pyenv_cfg.py) and Hypothesis property tests over PyEnvCfg read/write round trips, confirming the fix targets the general injection invariant rather than a single payload. The affected package is identified by CPE cpe:2.3:a:pypa:virtualenv:*:*:*:*:*:*:*:*, i.e. all virtualenv releases below 21.7.11; the file is consumed by Python's own venv/site machinery, which is why tampering with 'home' can redirect interpreter resolution.
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
CVSS:4.0/AV:L/AC:L/AT:P/PR:N/UI:P/VC:L/VI:H/VA:L/SC:N/SI:N/SA:N
Local vector with no auth but AC:H and UI:R because a venv run must consume attacker-influenced prompt crossing a trust boundary; dominant integrity impact (interpreter substitution) with minor C/A.
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.7.11, PyEnvCfg.write() writes prompt values verbatim to the line-oriented pyvenv.cfg format while PyEnvCfg._read_values() parses the file with str.splitlines() and accepts the last value for duplicate keys. An attacker who influences --prompt, VIRTUALENV_PROMPT, or configuration input can insert a recognized line boundary and additional keys, including home, causing consumers to use an attacker-selected base interpreter or corrupted environment metadata. The security impact requires prompt input from outside the operator's trust boundary; directly supplied prompt content primarily corrupts the operator's own environment. This issue is fixed in version 21.7.11.
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
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
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
Virtualenv versions up to 20.36.1 is affected by improper link resolution before file access (CVSS 4.5).
EUVD-2026-89465
GHSA-9h9j-4vrj-gf7g
NVD
CVE.org
EPSS
Vulnrichment
Exploit-DB