fix(security): prevent Zip Slip path traversal vulnerability in input…#116
fix(security): prevent Zip Slip path traversal vulnerability in input…#116zhenliemao wants to merge 1 commit into
Conversation
…_handler
This change fixes CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') vulnerability by using Python 3.12+'s built-in parameter in extractall(), which automatically rejects:
- Path traversal sequences (../)
- Symbolic links
- Device files and other special files
Fixes NVIDIA#109
Signed-off-by: GitHub User <494822673@qq.com>
rng1995
left a comment
There was a problem hiding this comment.
Thanks for tackling Zip Slip — but as written this change will break all zip extraction rather than harden it.
Blocking — filter="data" is a tarfile feature, not zipfile:
The extraction filters from PEP 706 (filter="data") were added to tarfile.extractall() in Python 3.12. zipfile.ZipFile.extractall() has the signature extractall(path=None, members=None, pwd=None) and does not accept a filter keyword. So this line raises TypeError: ZipFile.extractall() got an unexpected keyword argument 'filter' for every zip — and that TypeError is not caught by the surrounding except zipfile.BadZipFile, so it propagates and aborts the scan. This would make the "all existing tests pass" claim unlikely to hold if any test exercises zip extraction.
Also worth noting: unlike tarfile, zipfile already sanitizes member paths — extract()/extractall() strip leading slashes, drive letters, and .. components, so a member named ../../evil.py is written inside the target directory, not above it. So the classic ../ traversal is already largely mitigated here.
Suggested approach (if you want defense-in-depth beyond zipfile's built-in stripping): validate each member's resolved destination before extracting, e.g.
dest = extract_dir.resolve()
with zipfile.ZipFile(zip_path, "r") as zf:
for member in zf.infolist():
target = (extract_dir / member.filename).resolve()
if not target.is_relative_to(dest): # py3.9+: str(target).startswith(...)
raise ValueError(f"Unsafe path in archive: {member.filename}")
zf.extractall(extract_dir)That closes symlink/absolute/traversal cases explicitly without relying on an API that doesn't exist on zipfile. Please also add a test that extracts a crafted archive containing a ../ entry and asserts nothing escapes the temp dir.
|
Heads up before this merges: the change is |
Summary
This PR fixes CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') vulnerability also known as Zip Slip.
Problem
The
_extract_zipmethod ininput_handler.pywas usingZipFile.extractall()without any path validation, which allowed malicious zip files containing path traversal sequences (../) to write files outside the intended extraction directory.Solution
Use Python 3.12+'s built-in
filter="data"parameter forextractall(), which automatically rejects dangerous entries:../or Windows equivalent\..)This is the official recommended secure extraction method from Python's standard library documentation.
Testing
skillspector scan malicious.zip
Impact
Fixes #109
Checklist