{"id":"PYSEC-2026-1273","summary":"Copier's safe template has filesystem write access outside destination path","details":"### 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\" \u003e forbidden.txt\nmkdir src/\necho \"bar\" \u003e \"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\" \u003e forbidden.txt\n    mkdir src/\n    echo \"bar\" \u003e \"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\\\u003cuser\u003e\\Temp\\test-copier-vulnerability`\n    echo \"foo\" \u003e 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\" \u003e \"src\\{{ pathjoin(drive, 'Users', '\u003cuser\u003e', '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.","aliases":["CVE-2025-55214","GHSA-p7q8-grrj-3m8w"],"modified":"2026-07-07T17:47:20.657869518Z","published":"2026-07-07T16:03:01.489150Z","references":[{"type":"WEB","url":"https://github.com/copier-org/copier/security/advisories/GHSA-p7q8-grrj-3m8w"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2025-55214"},{"type":"WEB","url":"https://github.com/copier-org/copier/commit/fdbc0167cc22780b497e4db176feaf6f024757d6"},{"type":"PACKAGE","url":"https://github.com/copier-org/copier"},{"type":"PACKAGE","url":"https://pypi.org/project/copier"},{"type":"ADVISORY","url":"https://github.com/advisories/GHSA-p7q8-grrj-3m8w"}],"affected":[{"package":{"name":"copier","ecosystem":"PyPI","purl":"pkg:pypi/copier"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"7.1.0"},{"fixed":"9.9.1"}]}],"versions":["7.1.0","7.2.0","8.0.0","8.1.0","8.2.0","8.3.0","9.0.1","9.1.0","9.1.1","9.2.0","9.3.0","9.3.1","9.4.0","9.4.1","9.5.0","9.6.0","9.7.0","9.7.1","9.8.0","9.9.0"],"database_specific":{"source":"https://github.com/pypa/advisory-database/blob/main/vulns/copier/PYSEC-2026-1273.yaml"}}],"schema_version":"1.7.5","severity":[{"type":"CVSS_V4","score":"CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:N/VI:H/VA:H/SC:N/SI:N/SA:N"}]}