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:
- An attacker crafts a malicious template repository
- They embed path traversal sequences in the template path:
trusted-prefix/../../../malicious-template - Copier's trust check sees the
trusted-prefixcomponent and marks the path as trusted - The actual resolved path points outside the trusted directory
- 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.Pathequality 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
- Pin minimum versions: Always specify
>=constraints that exclude known-vulnerable releases - Audit lockfiles: Regularly run
trivy fs --scanners vuln .on repository lockfiles - Review template sources: Even with fixes, verify template repositories before execution
- 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.lockfor 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.0constraint inpyproject.tomlallowed 9.15.0, which used insufficient path validation - Lockfiles require active maintenance —
uv.lockpinned the vulnerable 9.15.0 with hash57b951d9f63b6b9d6ce3907fb1bd4672f60e2819a42393b971122d480059383f; 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.Pathdocumentation: 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)