PYSEC-2026-4013
Vulnerability from pysec - Published: 2026-09-18 04:37 - Updated: 2026-09-30 16:13The generated activate (bash/zsh) and activate.fish scripts interpolate a
shlex.quote-ed value into a position that quotes it a second time. The extra
quotes terminate the quoted run early and leave part of the value parsed as
shell code, so a path containing shell metacharacters runs commands when a user
sources the activation script.
activate is affected through the virtual environment's own path, on the branch
that reports a relocated environment (Virtual environment directory
__VIRTUAL_ENV__ does not exist!). For a destination named x'$(id)'y,
shlex.quote emits 'x'"'"'$(id)'"'"'y'; the inner " closes the enclosing
double quote and $(id) is left unquoted. This branch runs whenever the
recorded path is absent, which is the normal case for a virtual environment
copied or distributed to another machine.
activate.fish is affected through the interpreter's Tcl/Tk library paths
(set -gx TCL_LIBRARY '__TCL_LIBRARY__'). The rendered line becomes
''/tcl/(cmd)/lib'', and fish expands the (cmd) left between the adjacent
quoted runs. The same doubling splits a path containing a space into two list
elements, corrupting TCL_LIBRARY and TK_LIBRARY.
This is the same defect class as GHSA-x78j-v8h9-3j2q, which covered
activate.bat.
Fixed in 21.7.13 by moving the placeholders outside the surrounding quotes, so
each value keeps only the quoting shlex.quote applied.
| Name | purl | virtualenv | pkg:pypi/virtualenv |
|---|
{
"affected": [
{
"package": {
"ecosystem": "PyPI",
"name": "virtualenv",
"purl": "pkg:pypi/virtualenv"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "21.7.13"
}
],
"type": "ECOSYSTEM"
}
],
"versions": [
"0.8",
"0.8.1",
"0.8.2",
"0.8.3",
"0.8.4",
"0.9",
"0.9.1",
"0.9.2",
"1.0",
"1.1",
"1.10",
"1.10.1",
"1.11",
"1.11.1",
"1.11.2",
"1.11.3",
"1.11.4",
"1.11.5",
"1.11.6",
"1.2",
"1.3",
"1.3.1",
"1.3.2",
"1.3.3",
"1.3.4",
"1.4",
"1.4.1",
"1.4.2",
"1.4.3",
"1.4.4",
"1.4.5",
"1.4.6",
"1.4.7",
"1.4.8",
"1.4.9",
"1.4rc1",
"1.5",
"1.5.1",
"1.5.2",
"1.6",
"1.6.1",
"1.6.2",
"1.6.3",
"1.6.4",
"1.7",
"1.7.1",
"1.7.1.1",
"1.7.1.2",
"1.7.2",
"1.8",
"1.8.1",
"1.8.2",
"1.8.3",
"1.8.4",
"1.9",
"1.9.1",
"12.0",
"12.0.1",
"12.0.2",
"12.0.4",
"12.0.5",
"12.0.6",
"12.0.7",
"12.1.0",
"12.1.1",
"13.0.0",
"13.0.1",
"13.0.2",
"13.0.3",
"13.1.0",
"13.1.1",
"13.1.2",
"14.0.0",
"14.0.1",
"14.0.2",
"14.0.3",
"14.0.4",
"14.0.5",
"14.0.6",
"15.0.0",
"15.0.1",
"15.0.2",
"15.0.3",
"15.1.0",
"15.2.0",
"16.0.0",
"16.1.0",
"16.2.0",
"16.3.0",
"16.3.1.dev0",
"16.4.0",
"16.4.1",
"16.4.3",
"16.4.4.dev0",
"16.5.0",
"16.6.0",
"16.6.1",
"16.6.2",
"16.7.0",
"16.7.1",
"16.7.10",
"16.7.11",
"16.7.12",
"16.7.2",
"16.7.3",
"16.7.4",
"16.7.5",
"16.7.6",
"16.7.7",
"16.7.8",
"16.7.9",
"20.0.0",
"20.0.0b1",
"20.0.0b2",
"20.0.1",
"20.0.10",
"20.0.11",
"20.0.12",
"20.0.13",
"20.0.14",
"20.0.15",
"20.0.16",
"20.0.17",
"20.0.18",
"20.0.19",
"20.0.2",
"20.0.20",
"20.0.21",
"20.0.22",
"20.0.23",
"20.0.24",
"20.0.25",
"20.0.26",
"20.0.27",
"20.0.28",
"20.0.29",
"20.0.3",
"20.0.30",
"20.0.31",
"20.0.32",
"20.0.33",
"20.0.34",
"20.0.35",
"20.0.4",
"20.0.5",
"20.0.6",
"20.0.7",
"20.0.8",
"20.0.9",
"20.1.0",
"20.10.0",
"20.11.0",
"20.11.1",
"20.11.2",
"20.12.0",
"20.12.1",
"20.13.0",
"20.13.1",
"20.13.2",
"20.13.3",
"20.13.4",
"20.14.0",
"20.14.1",
"20.15.0",
"20.15.1",
"20.16.0",
"20.16.1",
"20.16.2",
"20.16.3",
"20.16.4",
"20.16.5",
"20.16.6",
"20.16.7",
"20.17.0",
"20.17.1",
"20.18.0",
"20.19.0",
"20.2.0",
"20.2.1",
"20.2.2",
"20.20.0",
"20.21.0",
"20.21.1",
"20.22.0",
"20.23.0",
"20.23.1",
"20.24.0",
"20.24.1",
"20.24.2",
"20.24.3",
"20.24.4",
"20.24.5",
"20.24.6",
"20.24.7",
"20.25.0",
"20.25.1",
"20.25.2",
"20.25.3",
"20.26.0",
"20.26.1",
"20.26.2",
"20.26.3",
"20.26.4",
"20.26.5",
"20.26.6",
"20.27.0",
"20.27.1",
"20.28.0",
"20.28.1",
"20.29.0",
"20.29.1",
"20.29.2",
"20.29.3",
"20.3.0",
"20.3.1",
"20.30.0",
"20.31.0",
"20.31.1",
"20.31.2",
"20.32.0",
"20.33.0",
"20.33.1",
"20.34.0",
"20.35.0",
"20.35.1",
"20.35.2",
"20.35.3",
"20.35.4",
"20.36.0",
"20.36.1",
"20.38.0",
"20.39.0",
"20.39.1",
"20.4.0",
"20.4.1",
"20.4.2",
"20.4.3",
"20.4.4",
"20.4.5",
"20.4.6",
"20.4.7",
"20.5.0",
"20.6.0",
"20.7.0",
"20.7.1",
"20.7.2",
"20.8.0",
"20.8.1",
"20.9.0",
"21.0.0",
"21.1.0",
"21.2.0",
"21.2.1",
"21.2.2",
"21.2.3",
"21.2.4",
"21.3.0",
"21.3.1",
"21.3.2",
"21.3.3",
"21.4.0",
"21.4.1",
"21.4.2",
"21.4.3",
"21.5.0",
"21.5.1",
"21.5.2",
"21.6.0",
"21.6.1",
"21.7.0",
"21.7.1",
"21.7.10",
"21.7.11",
"21.7.12",
"21.7.2",
"21.7.3",
"21.7.4",
"21.7.5",
"21.7.6",
"21.7.7",
"21.7.8",
"21.7.9"
]
}
],
"aliases": [
"CVE-2026-102925",
"GHSA-p58f-9548-mpm2"
],
"credits": [
{
"name": "Bern\u00e1t G\u00e1bor",
"type": "FINDER"
}
],
"details": "The generated `activate` (bash/zsh) and `activate.fish` scripts interpolate a\n`shlex.quote`-ed value into a position that quotes it a second time. The extra\nquotes terminate the quoted run early and leave part of the value parsed as\nshell code, so a path containing shell metacharacters runs commands when a user\nsources the activation script.\n\n`activate` is affected through the virtual environment\u0027s own path, on the branch\nthat reports a relocated environment (`Virtual environment directory\n__VIRTUAL_ENV__ does not exist!`). For a destination named `x\u0027$(id)\u0027y`,\n`shlex.quote` emits `\u0027x\u0027\"\u0027\"\u0027$(id)\u0027\"\u0027\"\u0027y\u0027`; the inner `\"` closes the enclosing\ndouble quote and `$(id)` is left unquoted. This branch runs whenever the\nrecorded path is absent, which is the normal case for a virtual environment\ncopied or distributed to another machine.\n\n`activate.fish` is affected through the interpreter\u0027s Tcl/Tk library paths\n(`set -gx TCL_LIBRARY \u0027__TCL_LIBRARY__\u0027`). The rendered line becomes\n`\u0027\u0027/tcl/(cmd)/lib\u0027\u0027`, and fish expands the `(cmd)` left between the adjacent\nquoted runs. The same doubling splits a path containing a space into two list\nelements, corrupting `TCL_LIBRARY` and `TK_LIBRARY`.\n\nThis is the same defect class as GHSA-x78j-v8h9-3j2q, which covered\n`activate.bat`.\n\nFixed in 21.7.13 by moving the placeholders outside the surrounding quotes, so\neach value keeps only the quoting `shlex.quote` applied.\n",
"id": "PYSEC-2026-4013",
"modified": "2026-09-30T16:13:20.520407Z",
"published": "2026-09-18T04:37:14Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/pypa/virtualenv/security/advisories/GHSA-p58f-9548-mpm2"
},
{
"type": "WEB",
"url": "https://github.com/pypa/virtualenv/pull/3252"
},
{
"type": "FIX",
"url": "https://github.com/pypa/virtualenv/commit/4d5a105ec2a2723b8c7f4571bb68f4f71d01e3f6"
},
{
"type": "WEB",
"url": "https://github.com/pypa/virtualenv/releases/tag/21.7.13"
},
{
"type": "PACKAGE",
"url": "https://github.com/pypa/virtualenv"
},
{
"type": "PACKAGE",
"url": "https://pypi.org/project/virtualenv"
}
],
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "virtualenv bash and fish activation scripts execute commands embedded in paths"
}
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Browse all ATT&CK techniques and the vulnerabilities related to each.
Related by attack behaviour
Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.