Poetry CVE-2026-41140
LOWAttack ChainAIDerived
Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain
-
ReconAttacker publishes malicious sdist to package index
-
DeliveryDeveloper runs poetry add malicious-package
-
ExploitPoetry fetches sdist and inspects metadata
-
Installextractall() called without path validation on vulnerable Python
-
C2Tar member with ../../ path extracted outside dest directory
-
ExecuteArbitrary file written to filesystem
-
ImpactPotential code injection or system compromise
Vulnerability Assessment
| Weakness |
CWE
OWASP Top 10:2025
A01:2025 - Broken Access Control
ASVS 5.0
V5 - File Handling Path canonicalization, traversal prevention
MITRE ATT&CK
2 techniques across 2 tactics: Discovery, Collection The technique list with ATT&CK links and the kill-chain view is part of the Basic plan and up. |
| Exploitation Conditions | Exploitation requires all of the following: (1) Poetry version prior to 2.3.4 installed and active; (2) Python version 3.10.0 through 3.10.12 or 3.11.0 through 3.11.4 running Poetry; (3) a crafted source distribution (sdist) with tar members containing path traversal sequences (e.g., ../../), symlinks pointing outside the extraction directory, or hardlinks targeting external files; (4) execution of a Poetry command that triggers tar extraction, specifically poetry add <malicious-package> (during dependency resolution) or poetry install with an sdist in the lock file. The exploitation is not automatically triggered during normal package installation from pre-built wheels (which do not invoke extractall()) and requires the presence of PKG-INFO metadata that lacks Requires-Dist fields, forcing Poetry to extract and inspect the sdist for dependency information. The attacker has no privileges requirement-exploitation works against default Poetry installations and configurations with no elevated permissions needed. |
| Impact | Despite a missing CVSS vector and score, this vulnerability carries moderate real-world risk when contextualized against available signals. The vulnerability requires three converging conditions: (1) a vulnerable Poetry version on an affected Python version, (2) dependency resolution or installation of a malicious sdist, and (3) network exposure during poetry add or poetry lock operations. The attack vector is network-adjacent (the attacker must craft and distribute a malicious sdist), but once a user attempts to add or lock dependencies, extraction occurs automatically without user interaction beyond normal Poetry commands. The vendor's own assessment states 'impact is low in practice' because a malicious sdist can already execute arbitrary code via setup.py during the build phase; however, the vulnerability enables file writes during tar extraction before the build backend runs, which is unexpected and violates least-privilege extraction semantics. No EPSS or KEV status is available, so exploitation probability cannot be quantified from official sources. The suggested patch (path validation with resolve() and is_relative_to() checks) is straightforward and has low implementation complexity, suggesting exploitation was not hardened by design complexity but rather by oversight. The scope is limited to specific Python minor versions, reducing affected population compared to a universal vulnerability. Organizations using affected configurations (Poetry + Python 3.10.0-3.10.12 or 3.11.0-3.11.4) should prioritize upgrading Poetry to 2.3.4 or later, but the urgency is moderate rather than critical, as the attack requires distribution and installation of a malicious package. |
| Exploit ScenarioDerived | An attacker publishes a malicious Python package to PyPI (or a private index) with a source distribution containing a crafted tarball with members named ../../etc/passwd or similar path traversal sequences. When a developer or CI/CD system runs poetry add malicious-package on a system with Poetry < 2.3.4 and Python 3.10.0-3.10.12 or 3.11.0-3.11.4, Poetry's dependency resolver extracts the sdist to inspect metadata. The unvalidated tar extraction writes files outside the package directory, potentially overwriting system files, injecting code into sibling projects, or poisoning the developer's environment before setup.py even runs. |
Get an e-mail when this CVE is exploited, patched or re-scored. Free account.
Alert meAnalysisAIv1 – Apr 22, 2026
Path traversal vulnerability in Poetry's tar extraction function allows arbitrary file writes when processing untrusted source distributions on Python 3.10.0-3.10.12 and 3.11.0-3.11.4, where the tarfile.data_filter safety mechanism is absent or broken. The vulnerability is triggered during dependency resolution (poetry add --lock) or installation before the build backend executes, enabling attackers to write files outside the intended extraction directory via crafted tar member paths, symlinks, or hardlinks in malicious sdists.
RemediationAI
Upgrade Poetry to version 2.3.4 or newer, which includes path validation in the extractall() function to reject tar members with paths traversing outside the target directory, symlinks pointing outside the boundary, and hardlinks targeting external files. This is the primary and recommended fix. If an immediate upgrade is not possible, restrict Poetry's operation to Python 3.11.5 or later, or Python 3.10.13 or later (where tarfile.data_filter is functional), by configuring poetry/python version constraints in your CI/CD and development environments. Additionally, audit dependency sources and avoid adding untrusted or unverified packages via poetry add, and enable dependency verification mechanisms (e.g., signed package indexes) if available. A temporary compensating control (not recommended long-term) is to run poetry add and poetry lock in isolated containers with restricted filesystem access, though this adds operational overhead and does not address the root vulnerability.
Affected Packages
Source: OSV (Open Source Vulnerabilities)
Affects your stack
Affects 1 package in pypi
Checking this CVE against your own stacks and servers is part of the Basic plan and up.
Technical ContextAI · show details
Poetry's extractall() function in src/poetry/utils/helpers.py (lines 410-426) conditionally applies tarfile.data_filter to defend against path traversal attacks, but only when the filter is available and not in a known-broken state. On affected Python versions (3.10.0-3.10.12, 3.11.0-3.11.4)-including Debian Bookworm's Python 3.11.2 and Ubuntu 22.04 LTS's Python 3.10.6-the fallback code path calls tarfile.extractall() without any path validation. This exposes three attack vectors: direct path traversal using ../../ path components in tar member names, symlink traversal where symlink targets escape the extraction boundary, and hardlink attacks that can read or overwrite arbitrary files. The root cause is CWE-22 (improper limitation of a pathname to a restricted directory), where untrusted tar archive content is extracted without validating member paths against the destination directory.
Know when Python gets its next vulnerability
- Watch products and get an email when something new is published
- Check this CVE against your own stack and servers
- Exploit and PoC references, threat intelligence from 22 sources
No credit card · 7-day full trial
Severity by source
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N/E:U
Primary rating from Vendor (https://github.com/python-poetry/poetry) · only source for this CVE.
CVSS VectorVendor: https://github.com/python-poetry/poetry
Lifecycle Timeline
3DescriptionCVE.org
Summary
The extractall() function in src/poetry/utils/helpers.py:410-426 extracts sdist tarballs without path traversal protection on Python versions where tarfile.data_filter is unavailable. Considering only Python versions which are still supported by Poetry, these are 3.10.0 - 3.10.12 and 3.11.0 - 3.11.4.
Impact
Arbitrary file write (path traversal) from untrusted sdist content.
In practice, the impact is low because an attacker who exploits this vulnerability can as well include arbitrary code in a setup.py, which will be executed when the sdist is built after tar extraction. In other words, a malicious sdist can write arbitrary files by design. However, since it is unexpected and not by design that the file write already happens during tar extraction, this is still considered a vulnerability.
On Python 3.11.2 (Debian Bookworm default, directly tested), a crafted sdist with ../../ tar member paths writes files outside the intended extraction directory. The traversal occurs during metadata resolution (poetry add --lock), before the build backend is run.
Affected Environments:
- Python 3.10.0 through 3.10.12 (inclusive):
tarfile.data_filterabsent or broken - Python 3.11.0 through 3.11.4 (inclusive):
tarfile.data_filterabsent or broken - Debian Bookworm: Python 3.11.2 (default)
- Ubuntu 22.04 LTS: Python 3.10.6 (default)
Patches
Versions 2.3.4 and newer of Poetry ensure that paths are inside the target directory.
Root Cause
File: src/poetry/utils/helpers.py, lines 410-426:
def extractall(source: Path, dest: Path, zip: bool) -> None:
"""Extract all members from either a zip or tar archive."""
if zip:
with zipfile.ZipFile(source) as archive:
archive.extractall(dest)
else:
broken_tarfile_filter = {(3, 9, 17), (3, 10, 12), (3, 11, 4)}
with tarfile.open(source) as archive:
if (
hasattr(tarfile, "data_filter")
and sys.version_info[:3] not in broken_tarfile_filter
):
archive.extractall(dest, filter="data")
else:
archive.extractall(dest)
# <-- NO FILTER: path traversalOn Python versions without a working tarfile.data_filter, the else branch at line 426 calls tarfile.extractall() without any filter or path validation. This enables three attack vectors:
- Direct path traversal: Tar members with
../../path components write files outside the extraction directory. - Symlink traversal: A symlink member pointing outside dest, followed by a file written through that symlink, escapes the boundary.
- Hardlink attacks: Hardlink members can read arbitrary files (same inode) or overwrite targets outside dest.
Call Sites
This function is called from two locations:
src/poetry/installation/chef.py:104(_prepare_sdist): Duringpoetry install/poetry addwhen building a package from sdist. Only triggered when the executor is enabled (actual installation).src/poetry/inspection/info.py:322(_from_sdist_file): During dependency resolution (poetry lock/poetry add). This path is reached when the sdist'sPKG-INFOlacksRequires-Distmetadata, forcing Poetry to extract the archive (and afterwards build the package).
Suggested Fix
Apply path validation in the else branch, covering direct traversal, symlinks, and hardlinks:
def extractall(source: Path, dest: Path, zip: bool) -> None:
"""Extract all members from either a zip or tar archive."""
if zip:
with zipfile.ZipFile(source) as archive:
archive.extractall(dest)
else:
broken_tarfile_filter = {(3, 9, 17), (3, 10, 12), (3, 11, 4)}
with tarfile.open(source) as archive:
if (
hasattr(tarfile, "data_filter")
and sys.version_info[:3] not in broken_tarfile_filter
):
archive.extractall(dest, filter="data")
else:
# Validate all member paths before extraction
dest_resolved = dest.resolve()
safe_members = []
for member in archive.getmembers():
member_path = (dest_resolved / member.name).resolve()
if not member_path.is_relative_to(dest_resolved):
raise ValueError(
f"Refusing to extract {member.name}: "
f"would write outside {dest}"
)
if member.issym():
link_target = (member_path.parent / member.linkname).resolve()
if not link_target.is_relative_to(dest_resolved):
raise ValueError(
f"Refusing symlink {member.name}: "
f"target {member.linkname} outside {dest}"
)
elif member.islnk():
link_target = (dest_resolved / member.linkname).resolve()
if not link_target.is_relative_to(dest_resolved):
raise ValueError(
f"Refusing hardlink {member.name}: "
f"target {member.linkname} outside {dest}"
)
safe_members.append(member)
archive.extractall(dest, members=safe_members)Threat Intelligence Overview
How this decision was reached
The engine reads each signal below and applies a fixed list of rules from top to bottom. The first rule that matches sets the recommended action – like a statement, every line is shown.
What every action level means
SSVC AssessmentENISA
Priority Score
Attack Technique
Path traversal exploits occur when applications use user-controlled input to construct file system paths without proper validation.
Remote Code Execution represents the critical moment when an attacker successfully runs arbitrary code on a target system without physical access.
Affected Products (CPE)CVE.org
Wazuh SIEM platform versions 4.4.0 through 4.9.0 contain an unsafe deserialization vulnerability in the DistributedAPI t
BentoML version 1.4.2 and earlier contains an unauthenticated remote code execution vulnerability through insecure deser
pgAdmin 4 contains critical remote code execution vulnerabilities in the Query Tool download and Cloud Deployment endpoi
The renderLocalView function in render/views.py in graphite-web in Graphite 0.9.5 through 0.9.10 uses the pickle Python
BentoML is a Python library for building online serving systems optimized for AI apps and model inference. Rated critica
OpenSSL before 0.9.8za, 1.0.0 before 1.0.0m, and 1.0.1 before 1.0.1h does not properly restrict processing of ChangeCiph
pyLoad download manager version prior to 0.5.0b3.dev77 exposes the Flask SECRET_KEY through an unauthenticated endpoint.
Langflow (a visual LLM pipeline builder) contains a critical unauthenticated code execution vulnerability (CVE-2026-3301
In Mercurial before 4.1.3, "hg serve --stdio" allows remote authenticated users to launch the Python debugger, and conse
Unauthenticated remote code execution affects Kestra OSS (the open-source event-driven orchestration platform) prior to
Unauthenticated remote code execution in Marimo ≤0.20.4 allows attackers to execute arbitrary system commands via the `/
pyLoad is the free and open-source Download Manager written in pure Python. Rated medium severity (CVSS 5.3), this vulne
GHSA-73h3-mf4w-8647
NVD
CVE.org
EPSS
Vulnrichment
VulDB
Exploit-DB