Skip to content

UPSTREAM PR #26908: java: limit numeric string length before BigDecimal parsing#141

Open
loci-dev wants to merge 2 commits into
mainfrom
loci/pr-26908-fix-java-bigdecimal-length-check
Open

UPSTREAM PR #26908: java: limit numeric string length before BigDecimal parsing#141
loci-dev wants to merge 2 commits into
mainfrom
loci/pr-26908-fix-java-bigdecimal-length-check

Conversation

@loci-dev
Copy link
Copy Markdown

Note

Source pull request: protocolbuffers/protobuf#26908

Summary

BigDecimal(String) has O(N²) time complexity for N-digit strings on JDK versions before 18 (JDK-8291514). Five JSON parser methods — parseInt32, parseInt64, parseUint32, parseUint64, and parseDouble — pass user-controlled strings directly to new BigDecimal() without length validation.

A single JSON numeric value with 1,000,000 digits takes ~13 seconds to parse on JDK 17. This can be used to DoS any service that parses protobuf JSON messages with numeric fields from untrusted input.

Benchmark (JDK 17, x86-64 Linux)

Digits BigDecimal construction time
1,000 1.8 ms
10,000 6.3 ms
100,000 133 ms
1,000,000 13.1 seconds

Fix

Added a parseBigDecimal() helper that rejects strings longer than 1000 characters before constructing BigDecimal. This is generous — valid protobuf numeric values never exceed ~350 characters (Double.MAX_VALUE in non-scientific notation is ~309 digits).

Affected JDK versions

  • JDK 8, 11, 17 (all current LTS releases): Vulnerable — no built-in string length limit in BigDecimal
  • JDK 18+: JDK itself limits BigDecimal string input to 1100 characters by default (JDK-8291514), but the protobuf-level check is still worthwhile as defense-in-depth

Test

Added testParserRejectOverlyLongNumericStrings covering all 5 affected field types.

BigDecimal(String) has O(N^2) time complexity for N-digit strings on
JDK versions before 18 (JDK-8291514). The JSON parser passes
user-controlled strings directly to BigDecimal in parseInt32,
parseInt64, parseUint32, parseUint64, and parseDouble, allowing a
single long numeric value to consume seconds of CPU.

Add a parseBigDecimal helper that rejects strings longer than 1000
characters before constructing BigDecimal. This is generous — valid
protobuf numeric values never exceed ~350 characters.
@loci-review
Copy link
Copy Markdown

loci-review Bot commented Apr 15, 2026

No meaningful performance changes were detected across 10167 analyzed functions in the following binaries: build.protoc-stable.

💬 Questions? Tag @loci-dev

@loci-dev loci-dev force-pushed the main branch 5 times, most recently from 2b89f87 to 2f65a6e Compare April 16, 2026 12:52
String.repeat() was added in Java 11. Use a StringBuilder loop instead
to maintain Java 8 compatibility per project requirements.
@loci-review
Copy link
Copy Markdown

loci-review Bot commented Apr 16, 2026

The analysis encountered an error. Please review the Processing Details for more information.

@loci-dev loci-dev force-pushed the main branch 19 times, most recently from fa0e9d9 to a96792a Compare April 21, 2026 16:47
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.

3 participants