chinabugotech/hutool · critical · UtilException

Zip bomb attack detected, invalid sizes: compressed {}, unco

Error message

Zip bomb attack detected, invalid sizes: compressed {}, uncompressed {}, name {}

What it means

ZipReader.checkZipBomb throws UtilException when a ZIP entry's uncompressed size exceeds compressed size by more than maxSizeDiff (default 100x), or when either size is negative. It is a security guard against zip-bomb archives that decompress to enormous volumes and exhaust memory/disk.

Source

Thrown at hutool-core/src/main/java/cn/hutool/core/compress/ZipReader.java:268

	 *
	 * @param entry {@link ZipEntry}
	 * @return 检查后的{@link ZipEntry}
	 */
	private ZipEntry checkZipBomb(ZipEntry entry) {
		if (null == entry) {
			return null;
		}
		if(maxSizeDiff < 0 || entry.isDirectory()){
			// 目录不检查
			return entry;
		}

		final long compressedSize = entry.getCompressedSize();
		final long uncompressedSize = entry.getSize();
		if (compressedSize < 0 || uncompressedSize < 0 ||
				// 默认压缩比例是100倍,一旦发现压缩率超过这个阈值,被认为是Zip bomb
				compressedSize * maxSizeDiff < uncompressedSize) {
			throw new UtilException("Zip bomb attack detected, invalid sizes: compressed {}, uncompressed {}, name {}",
					compressedSize, uncompressedSize, entry.getName());
		}
		return entry;
	}
}

View on GitHub (pinned to 8870454b2a)

Solutions

  1. If the high ratio is expected, raise the threshold: configure the reader with a larger maxSizeDiff (e.g. ZipReader.of(file).setMaxSizeDiff(1000)) before iterating.
  2. If you do not want the guard, disable it by setting maxSizeDiff to a negative value (guard is skipped when maxSizeDiff < 0).
  3. Validate the archive source / scan entries and reject entries with extreme ratios before delegating to ZipReader.
  4. Wrap the read loop in a try/catch on UtilException to skip or quarantine offending entries.

Example fix

// before
ZipReader.of(uploadFile).readAll();

// after - raise threshold for media-heavy archives
ZipReader.of(uploadFile)
    .setMaxSizeDiff(500)
    .readAll();
Defensive patterns

Strategy: validation

Validate before calling

// before reading, scan entries and reject extreme ratios
try (ZipFile zf = new ZipFile(file)) {
    final long MAX_RATIO = 100L;
    Enumeration<? extends ZipEntry> en = zf.entries();
    while (en.hasMoreElements()) {
        ZipEntry e = en.nextElement();
        if (!e.isDirectory() && e.getCompressedSize() > 0
                && e.getSize() > e.getCompressedSize() * MAX_RATIO) {
            throw new IOException("Refused zip entry with extreme ratio: " + e.getName());
        }
    }
}
// safe to pass to ZipReader now (or raise setMaxSizeDiff accordingly)

Try / catch

try {
    ZipReader.of(file).readAll();
} catch (UtilException e) {
    if (e.getMessage().contains("Zip bomb")) {
        // quarantine the file, log, reject the upload
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling ZipReader.of(file).read() / readNext() on an archive containing an entry where entry.getCompressedSize()*100 < entry.getSize(), or where the entry reports negative sizes. Only triggers when maxSizeDiff >= 0 and the entry is not a directory.

Common situations: Processing user-uploaded zip files; archives containing already-compressed payloads (zip-in-zip, JPEG/PDF media, encrypted zip) that legitimately exceed 100:1 ratio; malicious archives crafted to trigger the protection.

Related errors


AI-assisted analysis of chinabugotech/hutool@8870454b2a (2026-08-14). Data as JSON: /api/errors/01fa93abe93957d4. Report an issue: GitHub.