CVE-2026-34726
Description
Copier is a library and CLI app for rendering project templates. Prior to version 9.14.1, Copier's _subdirectory setting is documented as the subdirectory to use as the template root. However, the current implementation accepts parent-directory traversal such as .. and uses it directly when selecting the template root. As a result, a template can escape its own directory and make Copier render files from the parent directory without --UNSAFE. This issue has been patched in version 9.14.1.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Copier prior to 9.14.1 allowed template root escape via parent-directory traversal in _subdirectory, enabling unauthorized file rendering.
Vulnerability
Copier, a library and CLI tool for rendering project templates, contains a path traversal vulnerability in its _subdirectory setting. The _subdirectory field is intended to specify a subdirectory within the template to use as the root for rendering. However, the implementation accepts parent-directory traversal sequences such as .. and directly concatenates the rendered string with the template's local absolute path via self.template.local_abspath / subdir. This allows a template to escape its own directory and make Copier render files from parent directories without requiring the --UNSAFE flag [1].
Exploitation
An attacker can craft a malicious template that sets _subdirectory to a value like ../forbidden or an absolute path pointing outside the template root. When Copier processes the template, it resolves the path and walks that directory as the template root, effectively copying files from arbitrary locations on the filesystem. No special authentication or network position is required beyond the ability to supply a template to Copier (e.g., via a Git URL or local path) [1][4].
Impact
Successful exploitation allows an attacker to read and render files from directories outside the intended template root. This could lead to disclosure of sensitive information, such as configuration files or source code, that the template author did not intend to expose. The vulnerability bypasses the safety mechanism (--UNSAFE) that normally prevents such behavior [1].
Mitigation
The issue has been patched in Copier version 9.14.1. The fix introduces validation that rejects _subdirectory paths that resolve outside the template root, raising a ForbiddenPathError [4]. Users should upgrade to version 9.14.1 or later. No workaround is available for earlier versions [1].
AI Insight generated on May 18, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
copierPyPI | < 9.14.1 | 9.14.1 |
Affected products
1Patches
1cb80a3ffc9c3fix: disallow `_subdirectory` path outside template root
2 files changed · +71 −1
copier/_main.py+4 −1 modified@@ -1059,7 +1059,10 @@ def template_copy_root(self) -> Path: It points to the cloned template local abspath + the rendered subdir, if any. """ subdir = self._render_string(self.template.subdirectory) or "" - return self.template.local_abspath / subdir + path = (self.template.local_abspath / subdir).resolve() + if not path.is_relative_to(self.template.local_abspath): + raise ForbiddenPathError(path=Path(subdir)) + return path # Main operations @as_operation("copy")
tests/test_subdirectory.py+67 −0 modified@@ -7,6 +7,7 @@ import copier from copier._user_data import load_answersfile_data +from copier.errors import ForbiddenPathError from .helpers import BRACKET_ENVOPS_JSON, SUFFIX_TMPL, build_file_tree, git, git_init @@ -333,3 +334,69 @@ def test_new_version_changes_subdirectory( # Also assert the subdirectories themselves were not rendered assert not (dst / "subdir1").exists() assert not (dst / "subdir2").exists() + + +@pytest.mark.parametrize("is_absolute", [False, True]) +def test_subdirectory_path_outside_template_root_on_copy_raises_error( + tmp_path_factory: pytest.TempPathFactory, + is_absolute: bool, +) -> None: + src, dst = map(tmp_path_factory.mktemp, ("src", "dst")) + build_file_tree( + { + src / "template" / "copier.yml": ( + f"_subdirectory: {src / 'forbidden' if is_absolute else '../forbidden'}" + ), + src / "forbidden" / "forbidden.txt": "forbidden", + } + ) + with pytest.raises(ForbiddenPathError, match="forbidden"): + copier.run_copy(str(src / "template"), dst) + + +@pytest.mark.parametrize("is_absolute", [False, True]) +def test_subdirectory_path_outside_template_root_on_update_raises_error( + tmp_path_factory: pytest.TempPathFactory, + is_absolute: bool, +) -> None: + src, dst = map(tmp_path_factory.mktemp, ("src", "dst")) + build_file_tree( + { + src / "template" / "copier.yml": "_subdirectory: subdir", + src / "template" / "subdir" / "{{ _copier_conf.answers_file }}.jinja": ( + "{{ _copier_answers | to_nice_yaml }}" + ), + src / "template" / "subdir" / "file.txt": "v1 contents", + } + ) + with local.cwd(src / "template"): + git("init") + git("add", ".") + git("commit", "-m", "v1") + git("tag", "v1") + + copier.run_copy(str(src / "template"), dst) + assert load_answersfile_data(dst).get("_commit") == "v1" + assert (dst / "file.txt").exists() + assert (dst / "file.txt").read_text() == "v1 contents" + + with local.cwd(dst): + git("init") + git("add", ".") + git("commit", "-m", "v1") + + build_file_tree( + { + src / "template" / "copier.yml": ( + f"_subdirectory: {src / 'forbidden' if is_absolute else '../forbidden'}" + ), + src / "forbidden" / "forbidden.txt": "forbidden", + } + ) + with local.cwd(src / "template"): + git("add", ".") + git("commit", "-m", "v2") + git("tag", "v2") + + with pytest.raises(ForbiddenPathError, match="forbidden"): + copier.run_update(dst, overwrite=True)
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/copier-org/copier/commit/cb80a3ffc9c3787de3ed837e04ca29a0ff8ca3dfnvdPatchWEB
- github.com/copier-org/copier/security/advisories/GHSA-85v3-4m8g-hrh6nvdExploitVendor AdvisoryWEB
- github.com/advisories/GHSA-85v3-4m8g-hrh6ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2026-34726ghsaADVISORY
- github.com/copier-org/copier/releases/tag/v9.14.1nvdRelease NotesWEB
News mentions
1- How the Story of a USB Penetration Test Went ViralDark Reading · May 5, 2026