Hi,
The following vulnerabilities were published for python-virtualenv.
CVE-2026-113713[0]:
| virtualenv is a tool for creating isolated virtual python
| environments. From 21.14.8 until 21.14.10, the app-data seeder can
| leave an environment linked to temporary package files that
| virtualenv deletes when creation finishes. The environment-variable
| and configuration-file forms of symlink_app_data can enable this
| state even though the command-line flag is disabled for temporary
| app-data. The resulting environment depends on a cache pathname that
| its owner no longer controls. This issue is fixed in version
| 21.14.10.
CVE-2026-113714[1]:
| virtualenv is a tool for creating isolated virtual python
| environments. Prior to 21.14.9, download_wheel() writes package-
| index downloads directly into the reusable wheel/house cache before
| selecting a verification target from pip's textual Saved output.
| With default-index digest comparison enabled, a controlled package
| index can inject a misleading Saved line through a discarded link's
| data-requires-python attribute; this forged-line variant also
| requires knowledge of an absolute path to the genuine bundled wheel.
| The wrong path can then be hashed, while a digest mismatch leaves
| the rejected archive in the cache for later selection without
| verification. A separate rejected-cache-file variant requires
| control over downloaded data or archive selection but not the
| forged-line prerequisites. Explicit custom-index exceptions are
| outside the promised PyPI comparison, and the issue does not
| independently bypass TLS or establish control of default PyPI. This
| issue is fixed in version 21.14.9.
CVE-2026-113715[2]:
| virtualenv is a tool for creating isolated virtual python
| environments. Prior to 21.14.9, the stdlib venv creator reads
| generated pyvenv.cfg with str.splitlines() and merges parsed keys
| over virtualenv's selected configuration. An untrusted caller who
| influences the destination pathname can include a line-boundary
| character such as U+2028 to inject keys including home and include-
| system-site-packages, causing path data to change configuration
| structure before final output. Setting include-system-site-packages
| to true weakens environment isolation, while an altered home can
| change which standard-library files the interpreter loads if the
| attacker also controls that location. The builtin creator does not
| use this readback path. This issue is fixed in version 21.14.9.
CVE-2026-113716[3]:
| 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.
CVE-2026-113717[4]:
| virtualenv is a tool for creating isolated virtual python
| environments. Prior to 21.14.9, PipInvoke.get_pip_install_cmd()
| handles --seeder pip --download by calling get_wheel(download=False)
| and then allowing pip to consult the configured index, bypassing
| virtualenv's download_wheel() and verify_wheel_digest() path. When
| virtualenv's default-index PyPI digest comparison remains enabled,
| an index candidate matching the bundled package and version can
| therefore be selected without comparison to PyPI SHA-256 metadata.
| Explicit custom-index settings already opt out of that comparison
| and remain outside this verification-bypass claim; the demonstrated
| configuration used a non-PyPI index while leaving the index
| environment variables unset so the comparison policy remained
| active. This condition does not independently defeat TLS or
| establish control of the index response. This issue is fixed in
| version 21.14.9.
CVE-2026-113718[5]:
| virtualenv is a tool for creating isolated virtual python
| environments. Prior to 21.14.9, POSIX xonsh activation quote() uses
| repr() to write printable non-ASCII prompt or destination data into
| UTF-8 activate.xsh, while xonsh can read that script using
| $XONSH_ENCODING. Under a legacy multibyte codec such as GBK or Big5,
| a UTF-8 trail byte can consume the backslash before an adjacent
| quote, allowing the literal to close and attacker-influenced
| statements to execute when the user sources the generated script.
| This issue is fixed in version 21.14.9.
CVE-2026-113719[6]:
| virtualenv is a tool for creating isolated virtual python
| environments. Prior to 21.14.9,
| PipInstall._uninstall_previous_version() accepts existing seed-
| package metadata and _uninstall_dist() joins entries from
| top_level.txt and RECORD to site-packages without checking
| containment. When a reused destination contains distribution
| metadata influenced by another account, relative traversal, absolute
| entries, or linked parents can cause app-data reseeding to delete
| files outside the environment or the environment root with the
| invoking user's permissions, provided that user has deletion rights
| over the named paths. The deletion occurs during environment
| creation before any later use of the environment. Fresh environments
| without existing package metadata and creation with --clear do not
| enter this cleanup path. This issue is fixed in version 21.14.9.
CVE-2026-113720[7]:
| virtualenv is a tool for creating isolated virtual python
| environments. Prior to 21.14.9, the app-data copy seeder uses
| shutil.copy() to copy cached package files into later environments,
| causing cached source modes to override the current run's umask. A
| cache populated under a permissive umask can therefore produce files
| writable by another local account in a later traversable
| environment, allowing package code such as pip/__init__.py to be
| modified and executed by the environment owner. The attacker cannot
| force the earlier umask, and a private destination parent prevents
| access. This issue is fixed in version 21.14.9.
CVE-2026-113721[8]:
| 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.
CVE-2026-113722[9]:
| virtualenv is a tool for creating isolated virtual python
| environments. Prior to 21.14.9, virtualenv's ScriptMakerCustom and
| pip pass an incompletely quoted interpreter path to distlib
| ScriptMaker when generating POSIX console scripts. When the path
| contains a space or produces a shebang longer than 127 bytes,
| distlib emits a /bin/sh wrapper whose double-quoted interpreter path
| still expands command substitutions and backticks. An attacker who
| influences the environment destination can therefore execute
| commands with the user's privileges when the user later runs a
| generated launcher; environment creation and activation do not
| trigger the command. Existing launchers are not repaired by
| upgrading virtualenv alone and must be regenerated, while a later
| independent pip installation or upgrade can reintroduce an affected
| launcher because pip's vendored distlib is unchanged. The virtualenv
| fix is released in version 21.14.9.
CVE-2026-113723[10]:
| virtualenv is a tool for creating isolated virtual python
| environments. Prior to 21.14.9, caller-supplied prompt text can
| become executable syntax in the bash activation prompt. An attacker
| must influence the value passed to virtualenv, and a user must
| subsequently activate the environment and draw the prompt. This
| vulnerability is fixed in 21.14.9.
CVE-2026-113724[11]:
| virtualenv is a tool for creating isolated virtual python
| environments. Prior to 21.14.9, the safe_delete() deletion error
| handler responds to a failed removal by reading mode bits with
| os.lstat(path) and applying owner-write permission with
| os.chmod(path, ...), which follows a symlink. A planted link inside
| a read-only directory can therefore cause a victim-owned target
| outside the destination that is initially not writable by the
| invoking user to become broadly writable before the retry fails,
| provided that user owns the target and can change its mode. Another
| account can use the widened mode only if it can traverse the
| target's parent directories; root does not reach the demonstrated
| failure path, and the operation does not itself read the target.
| This issue is fixed in version 21.14.9.
CVE-2026-113725[12]:
| virtualenv is a tool for creating isolated virtual python
| environments. Prior to 21.14.7, the bash activate script escapes the
| environment name for only one of the two passes bash makes over PS1,
| so a backslash in the name undoes the escaping and a name containing
| \$(...) runs as commands in the user's shell each time bash draws
| the prompt. This issue is fixed in version 21.14.7.
CVE-2026-113726[13]:
| virtualenv is a tool for creating isolated virtual python
| environments. Prior to 21.13.0, the bash activate script that zsh
| also sources leaves the environment name unescaped; from 21.13.0
| until 21.14.4, it escapes backslashes, dollar signs, and backticks
| only when BASH_VERSION is set, so zsh receives the raw value. The
| script assigns that value to PS1. In zsh with PROMPT_SUBST, an
| attacker-influenced environment directory, --prompt, or
| VIRTUALENV_PROMPT value containing command, parameter, or arithmetic
| expansion syntax can therefore execute commands in the user's shell
| each time the prompt is drawn. A percent sign is separately
| interpreted as a zsh prompt escape but does not by itself execute
| commands. Plain zsh with PROMPT_SUBST disabled and bash are not
| affected by this mechanism. This issue is fixed in version 21.14.4.
CVE-2026-113732[14]:
| virtualenv is a tool for creating isolated virtual python
| environments. Prior to 21.14.2, FishActivator inherits
| ViaTemplateActivator.quote(), which uses POSIX shlex.quote() even
| though fish interprets backslashes and single quotes differently. An
| attacker-influenced environment path, --prompt, or VIRTUALENV_PROMPT
| value containing a backslash before a quote can therefore terminate
| the generated fish literal and execute command substitution when the
| user sources activate.fish. This issue is fixed in version 21.14.2.
CVE-2026-113776[15]:
| virtualenv is a tool for creating isolated virtual python
| environments. From 20.26.6 until 21.14.2,
| ViaTemplateActivator.instantiate_template() replaces placeholders
| one key at a time across the complete activation template, so
| trigger names such as __VIRTUAL_NAME__, __VIRTUAL_ENV__, or
| __VIRTUAL_PROMPT__ inside an already substituted and quoted
| environment path or prompt can be replaced during a later pass. The
| later value's quoting can close the earlier literal and execute the
| remaining path when a user activates the environment through bash,
| fish, xonsh, or activate_this.py. The distinct csh prompt-display
| token __VIRTUAL_PROMPT_DISPLAY_TCSH__ can instead break the
| generated script without establishing command execution. The
| attacker must influence the destination path or --prompt, and a
| value without a relevant placeholder name does not trigger this
| mechanism. This issue is fixed in version 21.14.2.
If you fix the vulnerabilities please also make sure to include the
CVE (Common Vulnerabilities & Exposures) ids in your changelog entry.
For further information see:
[0] https://security-tracker.debian.org/tracker/CVE-2026-113713
https://www.cve.org/CVERecord?id=CVE-2026-113713
[1] https://security-tracker.debian.org/tracker/CVE-2026-113714
https://www.cve.org/CVERecord?id=CVE-2026-113714
[2] https://security-tracker.debian.org/tracker/CVE-2026-113715
https://www.cve.org/CVERecord?id=CVE-2026-113715
[3] https://security-tracker.debian.org/tracker/CVE-2026-113716
https://www.cve.org/CVERecord?id=CVE-2026-113716
[4] https://security-tracker.debian.org/tracker/CVE-2026-113717
https://www.cve.org/CVERecord?id=CVE-2026-113717
[5] https://security-tracker.debian.org/tracker/CVE-2026-113718
https://www.cve.org/CVERecord?id=CVE-2026-113718
[6] https://security-tracker.debian.org/tracker/CVE-2026-113719
https://www.cve.org/CVERecord?id=CVE-2026-113719
[7] https://security-tracker.debian.org/tracker/CVE-2026-113720
https://www.cve.org/CVERecord?id=CVE-2026-113720
[8] https://security-tracker.debian.org/tracker/CVE-2026-113721
https://www.cve.org/CVERecord?id=CVE-2026-113721
[9] https://security-tracker.debian.org/tracker/CVE-2026-113722
https://www.cve.org/CVERecord?id=CVE-2026-113722
[10] https://security-tracker.debian.org/tracker/CVE-2026-113723
https://www.cve.org/CVERecord?id=CVE-2026-113723
[11] https://security-tracker.debian.org/tracker/CVE-2026-113724
https://www.cve.org/CVERecord?id=CVE-2026-113724
[12] https://security-tracker.debian.org/tracker/CVE-2026-113725
https://www.cve.org/CVERecord?id=CVE-2026-113725
[13] https://security-tracker.debian.org/tracker/CVE-2026-113726
https://www.cve.org/CVERecord?id=CVE-2026-113726
[14] https://security-tracker.debian.org/tracker/CVE-2026-113732
https://www.cve.org/CVERecord?id=CVE-2026-113732
[15] https://security-tracker.debian.org/tracker/CVE-2026-113776
https://www.cve.org/CVERecord?id=CVE-2026-113776
Regards,
Salvatore