Skip to content

Commit 77c0432

Browse files
authored
add a basic guard against mundane zipbombz (#13877)
* add a basic guard against mundane zipbombz * lint
1 parent beaa920 commit 77c0432

File tree

2 files changed

+28
-0
lines changed

2 files changed

+28
-0
lines changed

tests/unit/forklift/test_legacy.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,15 @@ def test_zipfile_unsupported_compression(self, tmpdir, method):
624624

625625
assert not legacy._is_valid_dist_file(f, "")
626626

627+
def test_zipfile_exceeds_compression_threshold(self, tmpdir):
628+
f = str(tmpdir.join("test.zip"))
629+
630+
with zipfile.ZipFile(f, "w") as zfp:
631+
zfp.writestr("PKG-INFO", b"this is the package info")
632+
zfp.writestr("1.dat", b"0" * 10240, zipfile.ZIP_DEFLATED)
633+
634+
assert not legacy._is_valid_dist_file(f, "")
635+
627636
def test_egg_no_pkg_info(self, tmpdir):
628637
f = str(tmpdir.join("test.egg"))
629638

warehouse/forklift/legacy.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import packaging_legacy.version
2929
import pkg_resources
3030
import requests
31+
import sentry_sdk
3132
import wtforms
3233
import wtforms.validators
3334

@@ -81,6 +82,8 @@
8182

8283
PATH_HASHER = "blake2_256"
8384

85+
COMPRESSION_RATIO_THRESHOLD = 10
86+
8487

8588
# Wheel platform checking
8689

@@ -670,6 +673,19 @@ def _is_valid_dist_file(filename, filetype):
670673
# If our file is a zipfile, then ensure that it's members are only
671674
# compressed with supported compression methods.
672675
if zipfile.is_zipfile(filename):
676+
# Ensure the compression ratio is not absurd (decompression bomb)
677+
compressed_size = os.stat(filename).st_size
678+
with zipfile.ZipFile(filename) as zfp:
679+
decompressed_size = sum(e.file_size for e in zfp.infolist())
680+
if decompressed_size / compressed_size > COMPRESSION_RATIO_THRESHOLD:
681+
sentry_sdk.capture_message(
682+
f"File {filename} ({filetype}) exceeds compression ratio "
683+
"of {COMPRESSION_RATIO_THRESHOLD} "
684+
"({decompressed_size}/{compressed_size})"
685+
)
686+
return False
687+
688+
# Check that the compression type is valid
673689
with zipfile.ZipFile(filename) as zfp:
674690
for zinfo in zfp.infolist():
675691
if zinfo.compress_type not in {
@@ -680,6 +696,9 @@ def _is_valid_dist_file(filename, filetype):
680696

681697
tar_fn_match = _tar_filenames_re.search(filename)
682698
if tar_fn_match:
699+
# TODO: Ideally Ensure the compression ratio is not absurd
700+
# (decompression bomb), like we do for wheel/zip above.
701+
683702
# Ensure that this is a valid tar file, and that it contains PKG-INFO.
684703
z_type = tar_fn_match.group("z_type") or ""
685704
try:

0 commit comments

Comments
 (0)