Skip to content

java: allow bounding decoder output to mitigate decompression bombs#1499

Open
hyperxpro wants to merge 1 commit into
google:masterfrom
hyperxpro:per-pull-cap
Open

java: allow bounding decoder output to mitigate decompression bombs#1499
hyperxpro wants to merge 1 commit into
google:masterfrom
hyperxpro:per-pull-cap

Conversation

@hyperxpro

@hyperxpro hyperxpro commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Motivation:
One-shot Decoder.decompress reads a whole stream into memory with no size limit, so a small malicious input can expand to gigabytes and crash the JVM. Streaming decode is already chunk-bounded (BrotliDecoderTakeOutput caps a chunk), so one-shot is the only exposed path.

Modification:
Added Decoder.Parameters with setMaxOutputSize, plus decompress(data, params) and decompress(data, offset, length, params) overloads. decompress throws once the decoded size passes the limit. This mirrors output_buffer_limit on the Python side and the existing Encoder.Parameters. Pure Java, no native change; existing decompress methods are unchanged.

Result:
Callers can cap one-shot decode output when reading untrusted input.

@eustas

eustas commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

Hi. Thanks for your PR. I like the intent and motivation, let's polish the implementation details.

It is not clearly stated in API, but BrotliDecoderTakeOutput (on top of which the decoding look is built) has natural limit; for simplicity, let's say it is 16MiB.

Idiomatic Java propels the IO chains to achieve desired properties. So, given that chunk size is not unbound, we should rely on user wits to wrap data source into limiting filter. Thus, the only vulnerable part is one-shot decoding.

(Truth to be said, one-shot decoding should never be used in production, only for tests / utils; but that is public API and we can't stop users from using it). Changes to decompress look good, but I don't like that second parameter changes it's function: when there are 2 parameters, it means limit, and when there are 4 parameters it means offset. I don't yet have crystallized vision, but it could be either "Options" approach, or "Lambda"/filter. NB: with filter we should not give access to ByteBuffer (it points to native decoder ring-buffer), but to chunk (copy of buffer).

Thanks again.

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.

2 participants