{"id":"CVE-2026-34726","aliases":["GHSA-85v3-4m8g-hrh6","PYSEC-2026-2134"],"url":"https://o3.security/vulnerability/CVE-2026-34726","summary":"Copier `_subdirectory` allows template root escape via parent-directory traversal","details":"### Summary\n\nCopier'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.\n\nAs a result, a template can escape its own directory and make Copier render files from the parent directory without `--UNSAFE`.\n\n### Details\n\nThe relevant code path is:\n\n1. the template defines `_subdirectory`\n2. Copier renders that string\n3. `template_copy_root` returns `self.template.local_abspath / subdir`\n4. Copier walks that directory as the template root\n\nRelevant code:\n\n- <https://github.com/copier-org/copier/blob/7aa7021bd73797c982492bac3535515d4484fdb7/copier/_main.py#L1056-L1062>\n- <https://github.com/copier-org/copier/blob/7aa7021bd73797c982492bac3535515d4484fdb7/copier/_template.py#L504-L513>\n\nThe effective sink is:\n\n```python\nsubdir = self._render_string(self.template.subdirectory) or \"\"\nreturn self.template.local_abspath / subdir\n```\n\nThere is no check that the resulting path stays inside the template directory.\n\nThe documentation for `_subdirectory` describes it as:\n\n> Subdirectory to use as the template root when generating a project.\n\nand explains it as a way to separate template metadata from template source code:\n\n<https://github.com/copier-org/copier/blob/7aa7021bd73797c982492bac3535515d4484fdb7/docs/configuring.md#L1582-L1646>\n\nThat description fits values like `template` or `poetry`, but not `..`.\n\n### PoC\n\n#### PoC 1: `_subdirectory: ..` escapes to the parent directory\n\n```sh\nmkdir -p root/template dst\necho 'loot' > root/loot.txt\nprintf '%s\\n' '_subdirectory: ..' > root/template/copier.yml\n\ncopier copy --overwrite root/template dst\nfind dst -maxdepth 3 -type f | sort\ncat dst/loot.txt\n```\n\nExpected output includes:\n\n```text\ndst/loot.txt\ndst/template/copier.yml\nloot\n```\n\nThis shows Copier is rendering from `root/` rather than from `root/template/`.\n\n### Impact\n\nIf a user runs Copier on an untrusted template, that template can change the effective template root and make Copier render files from outside the intended template directory.\n\nPractical impact:\n\n- template-root escape via `..`\n- rendering of parent-directory files that were not meant to be part of the template\n- possible without `--UNSAFE`","published":"2026-04-02T18:07:35.517Z","modified":"2026-08-12T03:51:25.358152540Z","cvss":{"score":4.4,"severity":"MEDIUM","vector":"CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N"},"epss":null,"cisaKev":null,"exploitsKnown":0,"affectedPackages":[{"ecosystem":"PyPI","name":"copier","fixedVersion":"9.14.1"}],"fix":{"url":"https://github.com/copier-org/copier/commit/cb80a3ffc9c3787de3ed837e04ca29a0ff8ca3df","label":"copier-org/copier@cb80a3f"},"references":[{"type":"WEB","url":"https://github.com/copier-org/copier/releases/tag/v9.14.1"},{"type":"ADVISORY","url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/34xxx/CVE-2026-34726.json"},{"type":"ADVISORY","url":"https://github.com/copier-org/copier/security/advisories/GHSA-85v3-4m8g-hrh6"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-34726"},{"type":"FIX","url":"https://github.com/copier-org/copier/commit/cb80a3ffc9c3787de3ed837e04ca29a0ff8ca3df"},{"type":"PACKAGE","url":"https://github.com/copier-org/copier"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-08-12T03:51:25.358152540Z"}}