---
id: "CVE-2026-113732"
kind: "vulnerability"
aliases: ["CVE-2026-113732", "GHSA-c947-3pg5-gm8q"]
title: "virtualenv activate.fish runs commands from a path or prompt with a backslash before a quote"
severity: "high"
cvss: 7.800000190734863
epss: 0.0021100000012665987
exploited: false
status: "open"
category: "package"
products: [{"name": "virtualenv", "fixed": ["21.14.2"], "affected": "<= 21.14.1", "ecosystem": "pypi"}]
ecosystems: ["pypi"]
tags: ["ci", "cwe-116", "cwe-78", "fish", "package", "python", "virtualenv"]
not_affected_if: ["bash-or-zsh-only", "managed-hosting", "no-fish-users"]
published_at: "2026-10-20T22:19:30+00:00"
first_seen_at: "2026-10-23T19:11:32+00:00"
updated_at: "2026-10-23T21:57:25+00:00"
sources: [{"source": "ghsa", "url": "https://github.com/advisories/GHSA-c947-3pg5-gm8q", "first_seen_at": "2026-10-23T19:11:32+00:00"}, {"source": "nvd", "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-113732", "first_seen_at": "2026-10-23T21:57:25+00:00"}]
---

# virtualenv activate.fish runs commands from a path or prompt with a backslash before a quote

virtualenv's generated activate.fish script quotes the environment path and prompt with POSIX shlex rules, which fish reads differently, so a crafted path or prompt containing a backslash before a quote breaks out of the quoting. An attacker who controls a directory name or prompt value can get arbitrary shell commands run when a user sources activate.fish.

_Summary, check and fix written by a model from the sources; labelled as such._

## Affected

- pypi:virtualenv affected <= 21.14.1 fixed 21.14.2

## How to check

Check the installed version with `pip show virtualenv` and treat anything at or below 21.14.1 as affected.
For environments created by you or your CI, grep activate.fish for `set -gx VIRTUAL_ENV` and `VIRTUAL_ENV_PROMPT` and look for unexpected $( ) content.

## Fix

Upgrade virtualenv to 21.14.2 or later and recreate fish environments with it.
Until then, avoid backslashes in environment paths and prompts and inspect activate.fish before sourcing environments you did not create.

## Timeline

- 2026-10-23T19:11:32+00:00 ghsa https://github.com/advisories/GHSA-c947-3pg5-gm8q
- 2026-10-23T21:57:25+00:00 nvd https://nvd.nist.gov/vuln/detail/CVE-2026-113732

## From the sources

### Impact

`FishActivator` defines no `quote()`, so it inherits `ViaTemplateActivator.quote`, which returns `shlex.quote(string)`. That function follows POSIX `sh` rules, where a backslash inside single quotes stays a literal character. fish reads `\'` inside single quotes as an escaped quote and `\\` as an escaped backslash. A value with a backslash before a quote therefore ends the literal somewhere other than where `shlex.quote` put the end, and fish expands the command substitution that follows.

The environment path reaches `set -gx VIRTUAL_ENV`, and `--prompt` or `VIRTUALENV_PROMPT` reaches `set -gx VIRTUAL_ENV_PROMPT`. For `--prompt "x\'\$(touch PWNED)'\'"`, the generated `activate.fish` contains:

```fish
set -gx VIRTUAL_ENV_PROMPT 'x\'"'"'$(touch PWNED)'"'"'\'"'"''
```

`source bin/activate.fish` runs `touch PWNED`, and fish prints no error. The same payload as a directory name runs through `VIRTUAL_ENV`. `--prompt .` takes the current directory's name, so running virtualenv inside a directory someone else named is enough. Without the backslash the payload runs nothing, and under bash it runs nothing either.

virtualenv generates `activate.fish` by default. An attacker needs to influence the environment path or prompt: a CI job or wrapper tool that passes a branch, project or job name through, or a directory in a cloned repository or unpacked archive.

The bug affects every release up to 21.14.1 that ships `activate.fish`. The GHSA-p58f-9548-mpm2 fix in 21.7.13 moved the placeholders outside their quotes but kept `shlex.quote`.

### Patches

Fixed in 21.14.2. `activate.fish` now escapes backslashes and single quotes the way fish reads them, so the example above runs nothing and shows the prompt as given. Fix: https://github.com/pypa/virtualenv/commit/3bddeaf8d02c3ee7f576503efb082f8f494cfcab

### Workarounds

Do not create an environment whose path or prompt contains a backslash, and inspect `activate.fish` before you source one you did not create.

### Credits

Kevin Stubbings (@Kwstubbs) of GitHub Security Lab reported this issue.

---

_Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai_
