From de5f7e3241333b7098610b594410a2d305b2a032 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 29 May 2024 15:40:58 +0200 Subject: [PATCH] Fix handling of zip bombs when unzipping archives --- src/Composer/Downloader/ZipDownloader.php | 24 +++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Composer/Downloader/ZipDownloader.php b/src/Composer/Downloader/ZipDownloader.php index cbd7d0452..5b6571dc1 100644 --- a/src/Composer/Downloader/ZipDownloader.php +++ b/src/Composer/Downloader/ZipDownloader.php @@ -144,6 +144,10 @@ class ZipDownloader extends ArchiveDownloader throw $processError; } + if (str_contains($processError->getMessage(), 'zip bomb')) { + throw $processError; + } + if (!is_file($file)) { $io->writeError(' '.$processError->getMessage().''); $io->writeError(' This most likely is due to a custom installer plugin not handling the returned Promise from the downloader'); @@ -208,6 +212,26 @@ class ZipDownloader extends ArchiveDownloader } else { $retval = $zipArchive->open($file); } + + $totalSize = 0; + $archiveSize = filesize($file); + $totalFiles = $zipArchive->count(); + if ($totalFiles > 0) { + for ($i = 0; $i < min($totalFiles, 5); $i++) { + $stat = $zipArchive->statIndex(random_int(0, $totalFiles - 1)); + if ($stat === false) { + continue; + } + $totalSize += $stat['size']; + if ($stat['size'] > $stat['comp_size'] * 200) { + throw new \RuntimeException('Invalid zip file with compression ratio >99% (possible zip bomb)'); + } + } + if ($archiveSize !== false && $totalSize > $archiveSize * 100 && $totalSize > 50*1024*1024) { + throw new \RuntimeException('Invalid zip file with compression ratio >99% (possible zip bomb)'); + } + } + if (true === $retval) { $extractResult = $zipArchive->extractTo($path);