new file mode 100644
@@ -0,0 +1,133 @@
+From 602b26623a724827ff171bf11fef4ad186d01f74 Mon Sep 17 00:00:00 2001
+From: Bernát Gábor <gaborjbernat@gmail.com>
+Date: Wed, 30 Sep 2026 23:01:05 -0700
+Subject: [PATCH] Merge commit from fork
+
+instantiate_template replaced one placeholder at a time across the whole
+template, so a placeholder name inside an already quoted value, such as a
+parent directory named __VIRTUAL_NAME__, was rewritten from inside the
+finished literal. The second value's quotes closed the first, and the rest
+of the path ran as code in bash, fish, xonsh and activate_this.py; in csh
+the prompt display tokens broke activate.csh the same way.
+
+Build every token's final text first and substitute them in one regex pass,
+with the csh display tokens joining that pass through substitutions().
+
+CVE: CVE-2026-113776
+Upstream-Status: Backport [https://github.com/pypa/virtualenv/commit/602b26623a724827ff171bf11fef4ad186d01f74]
+
+Backport Changes:
+- Omit the Csh display-token override and its specific test: 21.2.1 has
+ no separate display-token substitution or prompt-literal helpers.
+ Its Csh activator uses the corrected shared template substitution.
+- Exercise upstream's placeholder-in-parent-directory regression through
+ the existing Bash relocation fixture, since 21.2.1 lacks the later
+ prompt-test fixture. Add direct one-pass substitution checks for the
+ existing Bash, Csh, Fish and Python activators, and retain the 21.2.1
+ special-character fixture's other characters.
+
+Signed-off-by: Hetvi Thakar <hthakar@cisco.com>
+---
+ src/virtualenv/activation/via_template.py | 21 +++++++++++++++++----
+ tests/conftest.py | 3 ++-
+ tests/unit/activation/test_activator.py | 16 ++++++++++++++++
+ tests/unit/activation/test_bash.py | 1 +
+ 4 files changed, 36 insertions(+), 5 deletions(-)
+
+diff --git a/src/virtualenv/activation/via_template.py b/src/virtualenv/activation/via_template.py
+index 926c2b0..3af9dc5 100644
+--- a/src/virtualenv/activation/via_template.py
++++ b/src/virtualenv/activation/via_template.py
+@@ -1,6 +1,7 @@
+ from __future__ import annotations
+
+ import os
++import re
+ import shlex
+ import sys
+ from abc import ABC, abstractmethod
+@@ -84,10 +85,22 @@ class ViaTemplateActivator(Activator, ABC):
+ # read content as binary to avoid platform specific line normalization (\n -> \r\n)
+ binary = read_binary(self.__module__, template)
+ text = binary.decode("utf-8", errors="strict")
+- for key, value in replacements.items():
+- value_uni = self._repr_unicode(creator, value)
+- text = text.replace(key, self.quote(value_uni))
+- return text
++ substitutions = self.substitutions(replacements, creator)
++ # one pass over the template, so a placeholder name inside an already quoted value (a path component named
++ # __VIRTUAL_NAME__) stays data instead of being rewritten by a later key from inside the finished literal
++ pattern = re.compile("|".join(re.escape(key) for key in sorted(substitutions, key=len, reverse=True)))
++ return pattern.sub(lambda match: substitutions[match.group()], text)
++
++ def substitutions(self, replacements: dict[str, str], creator: Creator) -> dict[str, str]:
++ """Map each placeholder to the final text that replaces it in the template.
++
++ :param replacements: the raw placeholder values
++ :param creator: the creator of the environment
++
++ :returns: the placeholder to substituted text mapping
++
++ """
++ return {key: self.quote(self._repr_unicode(creator, value)) for key, value in replacements.items()}
+
+ @staticmethod
+ def _repr_unicode(creator: Creator, value: str) -> str: # noqa: ARG004
+diff --git a/tests/conftest.py b/tests/conftest.py
+index 3ec4147..f27c450 100644
+--- a/tests/conftest.py
++++ b/tests/conftest.py
+@@ -279,7 +279,8 @@ def is_inside_ci():
+
+ @pytest.fixture(scope="session")
+ def special_char_name():
+- base = "'\";&&e-$ èрт