CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-113723

CVE-2026-113723: OS Command Injection via Unsafe Prompt Expansion in PyPA virtualenv

Alon Barad
Alon Barad
Software Engineer

Oct 24, 2026·5 min read·1 visit

Executive Summary (TL;DR)

Unsafe string replacement in virtualenv bash activation scripts allows arbitrary command execution via crafted prompt names during environment activation.

A command injection vulnerability in PyPA virtualenv prior to version 21.14.9 allows local attackers to execute arbitrary commands when a user sources a generated shell activation script containing a crafted prompt value.

Vulnerability Overview

PyPA virtualenv is a standard Python component used to create isolated virtual execution environments. During environment generation, virtualenv creates shell activation scripts (such as bin/activate) that modify shell settings, environment variables, and interactive command prompts.

In versions prior to 21.14.9, caller-supplied prompt identifiers supplied through the --prompt argument or environment settings are embedded into the interactive prompt string (PS1) inside bin/activate. The mechanism used to sanitize the custom prompt string relied on incomplete naive pattern replacements.

When a user sources an activation script where the prompt contains shell expansion syntax, such as command substitution constructs $() or backticks, the interactive shell evaluates the injected syntax during prompt rendering. This results in arbitrary code execution within the security context of the user sourcing the environment.

Root Cause Analysis

The underlying flaw resides in src/virtualenv/activation/bash/activate.sh. When custom prompts were supplied, virtualenv attempted to sanitize special prompt characters including backslashes, dollar signs, and backticks using Bash parameter substitution.

The initial implementation performed character replacements as follows:

_VIRTUAL_PROMPT="${_VIRTUAL_PROMPT//\\/\\\\\\\\}"
_VIRTUAL_PROMPT="${_VIRTUAL_PROMPT//\$/\\\$}"
_VIRTUAL_PROMPT="${_VIRTUAL_PROMPT//\`/\\\`}"

This escaping strategy was flawed because shell prompt parsing in Bash and compatible shells executes in multiple evaluation passes. First, Bash decodes standard backslash prompt escapes. Second, if promptvars is active or if the shell operates in POSIX compatibility mode, it performs parameter expansion, command substitution, and arithmetic expansion on the resulting string.

Because the escaping logic only neutralized single-pass expansions, characters that survived initial string decoding were subjected to a secondary evaluation pass. Furthermore, when non-Bash shells such as dash sourced the script, parameter substitution rules behaved differently, causing syntax errors or secondary parsing flaws.

Code Analysis & Patch Review

The remediation implemented in PR #3418 (commit 5f48d711731311428aebfae61d46957762155b22) changes the mechanism used to update PS1. Rather than evaluating and escaping variable content directly into the double-quoted string, the patched version defers evaluation by storing a literal variable reference.

The patch adds checks to ensure that PS1 modifications occur only when compatible shell instances (bash or zsh) are detected, bypassing unsupported POSIX shells like dash:

--- a/src/virtualenv/activation/bash/activate.sh
+++ b/src/virtualenv/activation/bash/activate.sh
@@ -137,29 +137,26 @@ else
         export TK_LIBRARY
     fi
 
-    if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT-}" ] ; then
+    if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT-}" ] &&
+        { [ -n "${BASH_VERSION-}" ] || [ -n "${ZSH_VERSION-}" ]; }; then
         _OLD_VIRTUAL_PS1="${PS1-}"
-        _VIRTUAL_PROMPT="${VIRTUAL_ENV_PROMPT}"
-        if [ -n "${BASH_VERSION-}" ]; then
-            _VIRTUAL_PROMPT="${_VIRTUAL_PROMPT//\\/\\\\\\\\}"
-            _VIRTUAL_PROMPT="${_VIRTUAL_PROMPT//\$/\\\$}"
-            _VIRTUAL_PROMPT="${_VIRTUAL_PROMPT//\`/\\\`}"
-        elif [ -n "${ZSH_VERSION-}" ]; then
-            _VIRTUAL_PROMPT="${_VIRTUAL_PROMPT//\\/\\\\}"
-            _VIRTUAL_PROMPT="${_VIRTUAL_PROMPT//\$/\\\$}"
-            _VIRTUAL_PROMPT="${_VIRTUAL_PROMPT//\`/\\\`}"
-        fi
-        if [ -n "${ZSH_VERSION-}" ]; then
-            _VIRTUAL_PROMPT="${_VIRTUAL_PROMPT//\%/%%}"
+        if [ -n "${BASH_VERSION-}" ] && { shopt -q promptvars || shopt -qo posix; }; then
+            PS1='(${VIRTUAL_ENV_PROMPT-}) '"${PS1-}"
+        else
+            _VIRTUAL_PROMPT="${VIRTUAL_ENV_PROMPT//\\/\\\\}"
+            if [ -n "${ZSH_VERSION-}" ]; then
+                _VIRTUAL_PROMPT="${_VIRTUAL_PROMPT//\$/\\\$}"
+                _VIRTUAL_PROMPT="${_VIRTUAL_PROMPT//\`/\\\`}"
+                _VIRTUAL_PROMPT="${_VIRTUAL_PROMPT//\%/%%}"
+            fi
+            PS1="(${_VIRTUAL_PROMPT}) ${PS1-}"
+            unset _VIRTUAL_PROMPT
         fi
-        PS1="(${_VIRTUAL_PROMPT}) ${PS1-}"
-        unset _VIRTUAL_PROMPT
     fi

By assigning PS1='(${VIRTUAL_ENV_PROMPT-}) '"${PS1-}", Bash treats VIRTUAL_ENV_PROMPT strictly as a literal variable reference during prompt rendering, entirely preventing shell command parsing of its inner content.

Exploitation & Attack Methodology

Exploitation requires an attacker to control the --prompt argument supplied during virtual environment creation or to influence the VIRTUAL_ENV_PROMPT environment variable prior to activation.

An attack scenario involves a shared repository or build configuration containing a pre-configured virtual environment generation script, where the prompt parameter is set to $(id > /tmp/pwned). When virtualenv builds the environment, it writes the raw or inadequately escaped string into bin/activate.

virtualenv --prompt '$(id > /tmp/pwned)' .venv

When a user or automated pipeline executes source .venv/bin/activate, the shell reads the PS1 configuration. Upon rendering the primary prompt in the terminal, the subshell invocation executes id > /tmp/pwned without producing syntax errors.

Impact Assessment

Successful exploitation leads to arbitrary command execution in the context of the user running the interactive shell session. If an administrator or developer sources a compromised virtual environment activation script, the payload executes with their full privileges.

This vulnerability impacts developer workstations, continuous integration and continuous deployment (CI/CD) pipelines, and automated build scripts that dynamically construct virtual environments based on external repository metadata.

The CVSS v4.0 score is rated at 7.1 (High) with vector string CVSS:4.0/AV:L/AC:H/AT:P/PR:N/UI:A/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N. Exploitation requires local user interaction to source the generated script.

Remediation & Detection Guidance

To resolve this vulnerability, update virtualenv to version 21.14.9 or later using standard package management tooling:

pip install --upgrade "virtualenv>=21.14.9"

Existing virtual environments constructed prior to the update retain vulnerable bin/activate scripts. System administrators must regenerate existing virtual environments to ensure patched activation templates are written to disk.

Alternatively, users can set the VIRTUAL_ENV_DISABLE_PROMPT=1 environment variable prior to activation. This setting bypasses PS1 prompt modification entirely, preventing command evaluation regardless of virtualenv version.

Official Patches

PyPAGitHub Security Advisory GHSA-6w3r-xr62-4xcp
PyPAPull Request #3418: Fix PS1 escaping logic

Fix Analysis (1)

Technical Appendix

CVSS Score
7.1/ 10
CVSS:4.0/AV:L/AC:H/AT:P/PR:N/UI:A/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
EPSS Probability
0.14%
Top 97% most exploited

Affected Systems

PyPA virtualenv prior to version 21.14.9Linux, macOS, and Unix systems sourcing Bash/Zsh activation scripts

Affected Versions Detail

Product
Affected Versions
Fixed Version
virtualenv
PyPA
< 21.14.921.14.9
AttributeDetail
CWE IDCWE-78
CVSS v4.0 Score7.1 (High)
Attack VectorLocal
EPSS Score0.00142 (3.23th percentile)
CISA KEVNot Listed
Exploit StatusProof of Concept Available
ImpactArbitrary Code Execution

MITRE ATT&CK Mapping

T1059Command and Scripting Interpreter
Execution
T1059.004Unix Shell
Execution
CWE-78
Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')

The software constructs an OS command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended OS command when sent to a downstream component.

Known Exploits & Detection

GitHub Security AdvisoryAdvisory detailing proof-of-concept command injection via crafted prompt strings.

Vulnerability Timeline

Fix commit merged in PyPA virtualenv repository via Pull Request #3418.
2026-10-16
GitHub Security Advisory GHSA-6w3r-xr62-4xcp and CVE-2026-113723 published.
2026-10-20
virtualenv version 21.14.9 officially released.
2026-10-20

References & Sources

  • [1]GitHub Security Advisory GHSA-6w3r-xr62-4xcp
  • [2]Fix Commit 5f48d711731311428aebfae61d46957762155b22
  • [3]GitHub Pull Request #3418
  • [4]virtualenv Release 21.14.9
  • [5]NIST NVD CVE-2026-113723 Record
  • [6]CVE Program Record

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•about 2 hours ago•CVE-2026-113720
4.4

CVE-2026-113720: Local Permission Inheritance Vulnerability in virtualenv

virtualenv prior to version 21.14.9 contains a local permission inheritance vulnerability in its app-data copy seeder. Due to the reliance on Python's standard shutil.copy() function, permissions from cached packages are replicated directly onto newly created virtual environment files, ignoring the active process umask and allowing unprivileged local attackers to inject code.

Amit Schendel
Amit Schendel
5 views•5 min read
•about 3 hours ago•CVE-2026-113718
7.1

CVE-2026-113718: Code Injection in pypa/virtualenv XonshActivator via Multibyte Encoding Misalignment

A code injection vulnerability in pypa/virtualenv prior to version 21.14.9 allows arbitrary command execution in xonsh shells using legacy multibyte encodings when sourcing activate.xsh.

Amit Schendel
Amit Schendel
6 views•5 min read
•about 4 hours ago•CVE-2026-113714
2.3

CVE-2026-113714: Cache Poisoning and Unvalidated Wheel Download in virtualenv

Prior to version 21.14.9, virtualenv downloads wheel files directly into its reusable persistent cache directory prior to verifying PyPI digests or compatibility. Combined with unsanitized stdout parsing from pip, a controlled package index can cause virtualenv to calculate digests against pre-existing local files while leaving unverified archives in the shared persistent cache.

Amit Schendel
Amit Schendel
5 views•5 min read
•about 5 hours ago•CVE-2026-113717
2.3

CVE-2026-113717: Package Digest Verification Bypass in virtualenv Pip Seeder

A verification bypass vulnerability in virtualenv allows unverified Python wheel installation when using pip seeding with the download flag. Affected versions fail to perform SHA-256 digest validation against PyPI metadata before invoking pip.

Alon Barad
Alon Barad
6 views•5 min read
•about 6 hours ago•CVE-2026-113713
4.4

CVE-2026-113713: Insecure Temporary File Symlink Handling in PyPA virtualenv

Insecure temporary file usage (CWE-377) in virtualenv app-data seeder creates dangling symlinks pointing to deleted temporary directories, allowing local attackers on shared systems to execute arbitrary code.

Amit Schendel
Amit Schendel
5 views•4 min read
•about 7 hours ago•CVE-2026-112937
6.1

CVE-2026-112937: Arbitrary Directory Deletion via TOCTOU Race Condition in filelock ReadWriteLock

A Time-of-Check Time-of-Use (TOCTOU) race condition in the Python `filelock` library (versions 4.1.0 to 4.2.0) allows local unprivileged attackers to cause arbitrary directory deletion by swapping file system targets during lock cleanup or dead owner sweeps.

Alon Barad
Alon Barad
7 views•5 min read