GCVE Workshop - 22 September 2026 (14:00-18:00), Luxembourg Before The Vulnopticon Conference - Registration

GHSA-85V3-4M8G-HRH6

Vulnerability from github – Published: 2026-04-01 22:28 – Updated: 2026-04-06 17:32
VLAI
Summary
Copier `_subdirectory` allows template root escape via parent-directory traversal
Details

Summary

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.

Details

The relevant code path is:

  1. the template defines _subdirectory
  2. Copier renders that string
  3. template_copy_root returns self.template.local_abspath / subdir
  4. Copier walks that directory as the template root

Relevant code:

The effective sink is:

subdir = self._render_string(self.template.subdirectory) or ""
return self.template.local_abspath / subdir

There is no check that the resulting path stays inside the template directory.

The documentation for _subdirectory describes it as:

Subdirectory to use as the template root when generating a project.

and explains it as a way to separate template metadata from template source code:

https://github.com/copier-org/copier/blob/7aa7021bd73797c982492bac3535515d4484fdb7/docs/configuring.md#L1582-L1646

That description fits values like template or poetry, but not ...

PoC

PoC 1: _subdirectory: .. escapes to the parent directory

mkdir -p root/template dst
echo 'loot' > root/loot.txt
printf '%s\n' '_subdirectory: ..' > root/template/copier.yml

copier copy --overwrite root/template dst
find dst -maxdepth 3 -type f | sort
cat dst/loot.txt

Expected output includes:

dst/loot.txt
dst/template/copier.yml
loot

This shows Copier is rendering from root/ rather than from root/template/.

Impact

If 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.

Practical impact:

  • template-root escape via ..
  • rendering of parent-directory files that were not meant to be part of the template
  • possible without --UNSAFE
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "copier"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "9.14.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-34726"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-22"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-04-01T22:28:49Z",
    "nvd_published_at": "2026-04-02T19:21:32Z",
    "severity": "MODERATE"
  },
  "details": "### Summary\n\nCopier\u0027s `_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- \u003chttps://github.com/copier-org/copier/blob/7aa7021bd73797c982492bac3535515d4484fdb7/copier/_main.py#L1056-L1062\u003e\n- \u003chttps://github.com/copier-org/copier/blob/7aa7021bd73797c982492bac3535515d4484fdb7/copier/_template.py#L504-L513\u003e\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\u003e 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\u003chttps://github.com/copier-org/copier/blob/7aa7021bd73797c982492bac3535515d4484fdb7/docs/configuring.md#L1582-L1646\u003e\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 \u0027loot\u0027 \u003e root/loot.txt\nprintf \u0027%s\\n\u0027 \u0027_subdirectory: ..\u0027 \u003e 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`",
  "id": "GHSA-85v3-4m8g-hrh6",
  "modified": "2026-04-06T17:32:29Z",
  "published": "2026-04-01T22:28:49Z",
  "references": [
    {
      "type": "WEB",
      "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": "WEB",
      "url": "https://github.com/copier-org/copier/commit/cb80a3ffc9c3787de3ed837e04ca29a0ff8ca3df"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/copier-org/copier"
    },
    {
      "type": "WEB",
      "url": "https://github.com/copier-org/copier/releases/tag/v9.14.1"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Copier `_subdirectory` allows template root escape via parent-directory traversal"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Detection rules are retrieved from Rulezet.

Loading…

Loading…

Related by attack behaviour

Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.


Loading…