shutil.unpack_archive() on Windows writes outside extract_dir for ZIP entries with drive-prefixed names
Bug report
Bug description:
Summary
I found a Windows-specific issue in shutil.unpack_archive() when extracting ZIP files.
In Lib/shutil.py, the private helper _unpack_zipfile() skips names that start with / or contain .., but it does not reject or sanitize Windows drive-prefixed names such as D:/path/file.
On Windows, such names are joined into a drive-qualified path and can escape the intended extraction directory. As a result, a crafted ZIP archive can cause files to be written outside extract_dir.
Affected component
Lib/shutil.py_unpack_zipfile()
Impact
A crafted ZIP archive can cause an arbitrary file write outside extract_dir on Windows.
Trigger condition
- Platform: Windows
- Archive format: ZIP
- A ZIP entry name contains a drive prefix such as
D:/... extract_diris on a different drive
Tested environment
I reproduced this on Windows with Python 3.12.8.
Minimal reproduction
I attached a minimal repro script:
repro_shutil_unpack_zip_windows_drive_path_min.py
The repro creates a ZIP archive containing an entry like:
D:/shutil_outside_min.txt
and then calls:
shutil.unpack_archive(str(zip_path), str(extract_dir))
With extract_dir on another drive, the file is written outside the intended extraction directory.
Root cause
The validation in _unpack_zipfile() appears incomplete for Windows path semantics. Checking only for leading / and .. is not sufficient, because drive-prefixed paths such as D:/... are still treated as rooted or drive-qualified paths by Windows path handling.
For comparison, zipfile's own extraction logic strips drive information before extraction, but shutil._unpack_zipfile() does not.
Expected behavior
ZIP entries that are absolute, drive-prefixed, or otherwise resolve outside extract_dir on Windows should be rejected or normalized so that extraction always remains within extract_dir.
Actual behavior
A crafted ZIP entry with a drive prefix can escape extract_dir and be written to another location.
Additional context
I previously reported this privately to the Python Security Response Team on March 28, 2026, but I have not received a response yet, so I am opening this issue for tracking and triage.
I also attached a short write-up:
vuln_shutil_unpack_archive_zip_windows_drive_path.md
shutil_unpack_archive_zip_windows_drive_path_min.zip
CPython versions tested on:
CPython main branch, 3.14
Operating systems tested on:
Windows
Linked PRs
- gh-146581: Use ZipFile.extractall() in shutil for secure ZIP extraction #146588
- gh-146581: Fix vulnerability in shutil.unpack_archive() for ZIP files on Windows #146591
- [3.14] gh-146581: Fix vulnerability in shutil.unpack_archive() for ZIP files on Windows (GH-146591) #149064
- [3.13] gh-146581: Fix vulnerability in shutil.unpack_archive() for ZIP files on Windows (GH-146591) #149065
- [3.12] gh-146581: Fix vulnerability in shutil.unpack_archive() for ZIP files on Windows (GH-146591) #149066
- [3.11] gh-146581: Fix vulnerability in shutil.unpack_archive() for ZIP files on Windows (GH-146591) #149071
- gh-146581: Update docs for dangerous filenames in ZIP files #149994
- [3.15] gh-146581: Update docs for dangerous filenames in ZIP files (GH-149994) #150064
- [3.14] gh-146581: Update docs for dangerous filenames in ZIP files (GH-149994) #150065
- [3.13] gh-146581: Update docs for dangerous filenames in ZIP files (GH-149994) #150066