Back to Blog
high SEVERITY5 min read

How Trust-Prefix Bypass via Path Traversal Happens in Python Copier and How to Fix It

CVE-2026-53951 is a high-severity path traversal vulnerability in Copier 9.15.0 that allowed attackers to bypass trust-prefix checks and execute tasks without user confirmation. Upgrading to Copier 9.15.2 eliminates this attack vector by properly validating file paths before task execution.

O
By Orbis AppSec
Published September 7, 2026Reviewed September 7, 2026

Answer Summary

CVE-2026-53951 is a path traversal vulnerability (CWE-22) in Python's Copier project templating tool, affecting versions 9.15.0 and earlier. The vulnerability allowed attackers to bypass Copier's trust-prefix security mechanism using directory traversal sequences (e.g., `../`), causing tasks to execute unprompted during template generation. The fix upgrades Copier from 9.15.0 to 9.15.2 in `pyproject.toml` and `uv.lock`, which implements proper path canonicalization and trust validation before executing lifecycle tasks.

Vulnerability at a Glance

cweCWE-22 (Improper Limitation of a Pathname to a Restricted Directory)
fixUpgrade Copier to 9.15.2 with hardened path canonicalization
riskArbitrary code execution via unprompted task execution
languagePython
root causeInsufficient path validation allowed `../` sequences to bypass trust-prefix checks
vulnerabilityPath Traversal / Trust-Prefix Bypass

Introduction

In a routine dependency audit, Trivy flagged a high-severity vulnerability in uv.lock that could silently compromise development workflows. The issue—CVE-2026-53951—resides in Copier 9.15.0, a popular Python project templating tool. A flaw in how Copier validates trusted template paths allowed attackers to bypass security prompts and execute arbitrary tasks through path traversal sequences.

The vulnerability is particularly insidious because Copier's trust-prefix mechanism is designed to protect developers from malicious templates. When this protection fails silently, automated CI/CD pipelines and developer workstations become execution vectors for supply chain attacks.

The Vulnerability Explained

Copier uses a trust system where templates from certain paths or URLs require explicit user confirmation before executing lifecycle tasks (defined in copier.yml or copier.yaml). These tasks can run arbitrary shell commands—making them powerful but dangerous.

The vulnerability exists because Copier 9.15.0 failed to properly canonicalize file paths before checking them against the trust-prefix allowlist. Consider this attack scenario:

  1. An attacker crafts a malicious template repository
  2. They embed path traversal sequences in the template path: trusted-prefix/../../../malicious-template
  3. Copier's trust check sees the trusted-prefix component and marks the path as trusted
  4. The actual resolved path points outside the trusted directory
  5. Tasks execute without user prompting, running attacker-controlled commands

The vulnerable dependency was locked in uv.lock at version 9.15.0:

-    "copier>=9.13.0",
+    "copier>=9.15.2",

And the specific vulnerable artifact:

 [[package]]
 name = "copier"
-version = "9.15.0"
+version = "9.17.2"
 source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/9e/ec/e67bcf9b867a47dd8cf98e8c8e27ee8cf638633f72c535372ce5e30ade80/copier-9.15.0.tar.gz", hash = "sha256:57b951d9f63b6b9d6ce3907fb1bd4672f60e2819a42393b971122d480059383f", size = 635532, upload-time = "2026-04-30T12:52:56.582Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/2e/4c/2e593d85827c49f478ea4925d1008a144bb8ff2189c6e9f405c37bb56edb/copier-9.17.2.tar.gz", hash = "sha256:02e9c0d05281603c06d52f48350e48ffca0b4283d9f025664fbce4befabaa555", size = 650501, upload-time = "2026-08-19T13:49:17.456Z" }

The size increase from 635,532 to 650,501 bytes in the source distribution reflects the security hardening added in the patch releases.

Real-World Impact

For development teams using Copier in CI/CD pipelines or automated onboarding workflows, this vulnerability creates a supply chain attack vector:

  • CI/CD compromise: Automated template updates could trigger malicious task execution
  • Developer workstation takeover: Local template generation with seemingly trusted sources executes hidden payloads
  • Lateral movement: Compromised templates could exfiltrate environment variables or SSH keys

The Fix

The remediation involved two coordinated changes to enforce the security boundary:

1. pyproject.toml — Version Constraint Update

 dependencies = [
-    "copier>=9.13.0",
+    "copier>=9.15.2",
 ]

This change sets the minimum secure version to 9.15.2, ensuring uv or pip will never resolve to the vulnerable 9.15.0 release.

2. uv.lock — Locked Artifact Update

 [[package]]
 name = "copier"
-version = "9.15.0"
+version = "9.17.2"

The lockfile update pins the exact verified artifact with new cryptographic hashes:

Attribute Old (Vulnerable) New (Fixed)
Version 9.15.0 9.17.2
sdist SHA256 57b951d9f63b6b9d6ce3907fb1bd4672f60e2819a42393b971122d480059383f 02e9c0d05281603c06d52f48350e48ffca0b4283d9f025664fbce4befabaa555
wheel SHA256 0f59c2ea36df42f3ded85c091c3f1e2c8d3814b537504f0abc8c2e508f7e013d 24757d8875cdf4e076ff338e5ea984e85f5d5da9afcecea8a9dde0f151310b19

Security Improvements in 9.15.2+

Copier 9.15.2 and subsequent releases implement:

  • Path canonicalization: All template paths are resolved to absolute, normalized forms before trust checks
  • Symlink traversal protection: Resolved paths are validated to prevent symlink-based escapes
  • Strict trust-prefix matching: The allowlist comparison uses pathlib.Path equality after resolution, not string prefix matching

The wheel size increase from 62,747 to 67,003 bytes reflects additional validation logic for secure path handling.

Prevention & Best Practices

For Copier Users

  1. Pin minimum versions: Always specify >= constraints that exclude known-vulnerable releases
  2. Audit lockfiles: Regularly run trivy fs --scanners vuln . on repository lockfiles
  3. Review template sources: Even with fixes, verify template repositories before execution
  4. Isolate CI/CD: Run Copier in ephemeral, least-privilege environments

For Python Developers

Risk Pattern Safe Alternative
path.startswith(trusted_prefix) pathlib.Path(path).resolve().is_relative_to(trusted_base)
String concatenation for paths pathlib.Path.joinpath() or / operator
os.path.normpath() alone os.path.realpath() with symlink resolution

Detection Tools

  • Trivy: Scans uv.lock, poetry.lock, Pipfile.lock for CVEs
  • Semgrep: Custom rules for path traversal patterns (https://semgrep.dev/r?q=python.lang.security.audit.path-traversal)
  • pip-audit: PyPI-specific vulnerability scanner
  • OWASP Dependency-Check: Multi-ecosystem dependency analysis

Key Takeaways

  • Never use string prefix matching for path trust decisions — the copier>=9.13.0 constraint in pyproject.toml allowed 9.15.0, which used insufficient path validation
  • Lockfiles require active maintenanceuv.lock pinned the vulnerable 9.15.0 with hash 57b951d9f63b6b9d6ce3907fb1bd4672f60e2819a42393b971122d480059383f; automated updates are essential
  • Task execution frameworks need strict path sandboxing — Copier's lifecycle tasks run shell commands, making path traversal a code execution vector
  • Supply chain security extends to development tools — Template generators, linters, and build tools are high-value attack targets

How Orbis AppSec Detected This

Component Details
Source pyproject.toml dependency declaration with unconstrained copier>=9.13.0
Sink Locked artifact resolution in uv.lock line 25: version = "9.15.0"
Missing control No minimum secure version constraint; no automated lockfile vulnerability scanning
CWE CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
Fix Updated constraint to copier>=9.15.2 and regenerated uv.lock with verified hashes

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.

Conclusion

CVE-2026-53951 demonstrates how path traversal vulnerabilities can undermine security architectures even when explicit trust mechanisms exist. The Copier trust-prefix bypass shows that path validation must happen after canonicalization, not before. For Python developers, this case reinforces the importance of:

  • Proactive dependency management with minimum secure versions
  • Automated vulnerability scanning of lockfiles
  • Understanding that >= constraints without upper bounds can silently admit vulnerable releases

The 9.15.2 upgrade path is straightforward and preserves all valid functionality while eliminating this attack vector. Teams using Copier should audit their lockfiles and CI/CD configurations for this vulnerability pattern.

References

  • CWE-22: Improper Limitation of a Pathname to a Restricted Directory: https://cwe.mitre.org/data/definitions/22.html
  • OWASP Path Traversal Prevention Cheat Sheet: https://cheatsheetseries.owasp.org/cheatsheets/Path_Traversal_Prevention_Cheat_Sheet.html
  • Python pathlib.Path documentation: https://docs.python.org/3/library/pathlib.html
  • Semgrep path traversal rules: https://semgrep.dev/r?q=python.lang.security.audit.path-traversal
  • GitHub PR: fix: upgrade copier to 9.15.2 (CVE-2026-53951)

Frequently Asked Questions

What is a trust-prefix bypass vulnerability?

A trust-prefix bypass occurs when security controls that restrict operations to trusted directory paths can be circumvented using path traversal techniques like `../` sequences, allowing access to files outside the intended scope.

How do you prevent path traversal in Python?

Use `os.path.realpath()` or `pathlib.Path.resolve()` to canonicalize paths, validate against allowed base directories with `os.path.commonpath()`, and never trust user-input paths without sanitization.

What CWE is path traversal?

CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

Is checking for `../` in strings enough to prevent path traversal?

No. Attackers can use encoded sequences, Unicode normalization, symlink traversal, or case variations. Always use proper path canonicalization APIs rather than string filtering.

Can static analysis detect trust-prefix bypass vulnerabilities?

Yes. Tools like Trivy, Semgrep, and CodeQL can flag unsafe path handling patterns, though comprehensive detection requires tracking tainted data flow from user input to file system operations.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #402

Related Articles

high

How Path Traversal Happens in TensorFlow's Data Service and How to Fix It

TensorFlow's data service dispatcher validated dataset IDs against forward-slash traversal attacks but overlooked backslash characters on non-Windows platforms, allowing attackers to escape the root directory. A targeted fix adds explicit backslash validation across all platforms, closing a high-severity path traversal vulnerability in the snapshot management system.

critical

How Command Injection happens in Python subprocess calls and how to fix it

A critical command injection vulnerability was discovered in `spider/php/crawler.py` where the `PHPBridge.call()` method passed unvalidated external arguments directly to `subprocess.run()`. An attacker controlling the `spider_path` or `method` parameters could execute arbitrary PHP scripts or inject malicious method names. The fix adds strict input validation — requiring `method` to be a valid Python identifier and `spider_path` to resolve to an existing `.php` file — before any subprocess exec

critical

How Path Traversal in basic-ftp Leads to File Overwrite Attacks and How to Fix It

CVE-2026-27699 is a critical path traversal vulnerability in basic-ftp versions before 5.3.1 that allows attackers to overwrite arbitrary files on the system by crafting malicious file paths. This vulnerability was fixed by upgrading basic-ftp and enforcing strict version constraints across dependent packages. Understanding this attack and its mitigation is essential for developers using FTP libraries in production environments.

critical

How Command Injection Vulnerabilities Happen in Python Subprocess Calls and How to Fix Them

A critical command injection vulnerability was discovered in `src/unused/server/fft.py` where external binaries like `oggenc` and `cocoa_text` were executed with file path parameters that could be manipulated by user input. Although `shell=False` was used, the lack of input validation allowed attackers to potentially trigger processing of arbitrary files or cause denial of service. This fix implements proper path validation to prevent exploitation.

critical

How Path Traversal happens in Node.js Express servers and how to fix it

A path traversal vulnerability in `src/server.js` allowed attackers to escape the intended wiki directory by sending encoded traversal sequences through the `/api/pages/:slug(*)` wildcard endpoint. The flawed `startsWith` boundary check could be bypassed after `decodeURIComponent` processing, potentially exposing arbitrary files on the server. The fix replaces the inline filesystem logic with a dedicated `readWikiPage()` function that enforces proper path validation.

high

How missing dependency update cooldowns happen in GitHub Dependabot configurations and how to fix it

A semgrep scan flagged `.github/dependabot.yml` for lacking a cooldown period, meaning Dependabot would immediately propose updates to brand-new package versions across npm, Bundler, and Docker ecosystems. The fix adds a `cooldown: default-days: 7` block to every `package-ecosystem` entry, forcing a one-week waiting period before newly published releases are considered — reducing exposure to malicious or unstable package drops.