Skip to content
Open
2 changes: 1 addition & 1 deletion Doc/library/shutil.rst
Original file line number Diff line number Diff line change
Expand Up @@ -715,7 +715,7 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules.
Never extract archives from untrusted sources without prior inspection.
It is possible that files are created outside of the path specified in
the *extract_dir* argument, e.g. members that have absolute filenames
starting with "/" or filenames with two dots "..".
starting with "/" or filenames with relative path components "../".

Since Python 3.14, the defaults for both built-in formats (zip and tar
files) will prevent the most dangerous of such security issues,
Expand Down
25 changes: 4 additions & 21 deletions Lib/shutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -1245,27 +1245,10 @@ def _unpack_zipfile(filename, extract_dir):
if not zipfile.is_zipfile(filename):
raise ReadError("%s is not a zip file" % filename)

zip = zipfile.ZipFile(filename)
try:
for info in zip.infolist():
name = info.filename

# don't extract absolute paths or ones with .. in them
if name.startswith('/') or '..' in name:
continue

targetpath = os.path.join(extract_dir, *name.split('/'))
if not targetpath:
continue

_ensure_directory(targetpath)
if not name.endswith('/'):
# file
with zip.open(name, 'r') as source, \
open(targetpath, 'wb') as target:
copyfileobj(source, target)
finally:
zip.close()
with zipfile.ZipFile(filename) as zf:
# delegate extracting the archive to zipfile
_ensure_directory(extract_dir)
zf.extractall(extract_dir)

def _unpack_tarfile(filename, extract_dir, *, filter=None):
"""Unpack tar/tar.gz/tar.bz2/tar.xz `filename` to `extract_dir`
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ZIP archive entries containing two dots ".." in their name caused shutil's unpack_archive method to silently skip these files during extraction. This has been fixed, shutil's unpack_archive method now generates the same results as Python's own extractall method in the zipfile module, or the Linux unzip tool.
Loading