Skip to content

fix(data): enforce decompression limit and reject payload on KMZ directory entries - #1792

Open
dkhawk wants to merge 1 commit into
mainfrom
fix/kmz-directory-decompression-limit
Open

dkhawk wants to merge 1 commit into
mainfrom
fix/kmz-directory-decompression-limit

Conversation

@dkhawk

@dkhawk dkhawk commented Sep 23, 2026

Copy link
Copy Markdown
Contributor

Fixes #1790

Problem

KMZ directory entries (names ending with /) were previously skipped in KmzParser without reading through CountingInputStream. When ZipInputStream.closeEntry() was subsequently called, the underlying runtime implementation silently inflated and discarded any compressed data payload within the directory entry without incrementing the uncompressed byte counter. An attacker could construct an archive containing a directory entry with a large compressed payload (e.g., 512 MiB compressed down to ~500 KB), bypassing the configured maxKmzUncompressedTotalSize (50 MiB default) and causing CPU starvation or ANR dialogs.

Solution

  1. Immediate Payload Detection on Directory Entries: Under PKWARE ZIP specifications, directory entries must not carry any data payload. Reading even a single byte from the directory entry detects rogue payloads immediately ((1)$) and throws an IOException without inflating the rest of the stream.
  2. Defense-in-Depth Draining: Added drainEntry(countingStream) prior to zipInputStream.closeEntry() to guarantee that any unread bytes in any entry pass through CountingInputStream and count towards maxKmzUncompressedTotalSize.
  3. Cleaned up redundant fully qualified exception types.

Testing

  • Added regression test parse rejects directory entry with payload exceeding decompression limit in KmzParserTest, reproducing the failure on unpatched code and verifying rejection with the fix.
  • Added parse allows legitimate empty directory entries in KmzParserTest verifying standard KMZ archives with directory entries parse cleanly.

@dkhawk
dkhawk marked this pull request as ready for review September 23, 2026 00:33
@dkhawk
dkhawk requested a review from kikoso September 23, 2026 00:33
@googlemaps-bot

googlemaps-bot commented Sep 23, 2026

Copy link
Copy Markdown
Contributor

Code Coverage

Overall Project 51.59% 🍏
Files changed 100% 🍏

Module Coverage
Kover Gradle Plugin XML report for :data 51% 🍏
Files
Module File Coverage
Kover Gradle Plugin XML report for :data KmzParser.kt 87.85% 🍏

…ctory entries

Fixes #1790

KMZ directory entries (names ending in '/') were previously skipped in KmzParser without reading through CountingInputStream. When ZipInputStream.closeEntry() was subsequently called, it silently inflated and discarded any compressed payload in the directory entry without counting the bytes towards maxKmzUncompressedTotalSize, allowing decompression exhaustion (Zip bomb DoS) to bypass the limit.

- Rejects KMZ directory entries carrying unexpected data payloads immediately on byte 1.
- Drains unread bytes through CountingInputStream prior to closeEntry() as defense-in-depth.
- Adds regression tests in KmzParserTest verifying directory entries with payloads are rejected and empty directory entries parse cleanly.
@dkhawk
dkhawk force-pushed the fix/kmz-directory-decompression-limit branch from 6d4f6b2 to b426719 Compare September 23, 2026 00:45

@LoyalAbbas LoyalAbbas left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@kikoso kikoso left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

KMZ directory entries bypass the cumulative decompression limit

4 participants