You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hi, I'd like to report a security issue in org.json that causes availability impact in applications that parse user-supplied JSON or XML.
Issue
When parsing a JSON or XML document containing a very large numeric literal (e.g. a number with tens of thousands of digits), the parser constructs a BigInteger or BigDecimal object from the raw string with no length limit. Because BigInteger construction has super-linear time complexity, a moderately sized request body can cause a server thread to block for several seconds.
This issue is present in JSONTokener.java and JSONObject.java. It affects all three primary parsing entry points: new JSONObject(String), new JSONArray(String), and XML.toJSONObject(String). No existing JSONParserConfiguration option (including withStrictMode(true)) prevents the behavior.
Affected versions: 20150729 through 20260522 (all releases since BigInteger/BigDecimal support was added).
CVSS 3.1: 5.9 Medium — AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H
CWE: CWE-400, CWE-770
Note on prior CVEs:
This is distinct from CVE-2022-45688 (XML nesting depth → StackOverflow) and CVE-2023-5072 (JSON structural nesting → StackOverflow). Both of those issues involve recursive call-stack depth and were fixed by catching StackOverflowError or adding a maxNestingDepth guard. The numeric string length issue is in a different code path and has not been addressed by either fix.
Suggested fix
Add a configurable maximum numeric literal length to JSONParserConfiguration, similar to Jackson's StreamReadConstraints.withMaxNumberLength() introduced in Jackson 2.15 (April 2023) with a default of 1,000 characters. A guard inside the accumulation loop in nextSimpleValue() would prevent construction of BigInteger/BigDecimal from excessively long strings.
Full security advisory available upon request via private channel.
have u got a chance to look into above PoC code and try? Thx.
Yes, the problem has been recreated and confirmed. Also found a related issue where using scientific notation for very large numbers results in an uncaught NumberFormatException. Timeframe to fix both issues is about 2 weeks. Feel free to go ahead and create a CVE, if you wish.
have u got a chance to look into above PoC code and try? Thx.
Yes, the problem has been recreated and confirmed. Also found a related issue where using scientific notation for very large numbers results in an uncaught NumberFormatException. Timeframe to fix both issues is about 2 weeks. Feel free to go ahead and create a CVE, if you wish.
Thank you for the confirmation. I will apply to reserve a CVE ID.
BTW, would you consider enabling the Security Advisory feature within this repo?
@stleary Thanks for the quick actions. I have raised a security advisory for this issue with all the details on my hand.
Please review and check there, modify it if you have any other suggestions about fix, etc.
After you patched this issue with a new release version, we could add it as the Patched versions within that security advisory and then publish it.
Finally Github Dependabot will automatically notify users who depend on JSON-java about this security advisory.
Too-large exponential form (ex 1e999999999999) in a JSONObject or JSONArray:
NumberFormatException is thrown from static method JSONObject.getNumber()
Caught by static method JSONObject.stringToNumber()
Returned as an unconverted String.
This behavior goes back at least to 20210307. No changes planned at this time.
Too-long exponential form string is handled the same way, by returning the unconverted String.
Too-long non-negative natural number
Time-consuming call to new BigInteger() in static method JSONObject.stringToNumber()
Too-long decimal or negative natural number:
Time-consuming call to new BigDecimal() in static method JSONObject.getNumber()
The default and max number length properties will be stored in the base class ParserConfiguration.
For now, this implementation will have a 1000-char fixed limit for parsing big numbers.
Max scientific notation conversions will have fixed max exponent value of +/-Math.pow(2, 32) i.e. about 2 billion.
Max digits in coefficient TBD
Invalid numeric values will be converted to String instead of throwing an exception, since this behavior is already in place for too-large exponential form. The JSONArray and XML parsers will have the same behavior. Note that the concern is for parsing text to JSON, not for retrieving values from a JSONObject or JSONArray.
The methods objectToBigInteger(), objectToBigDecimal(), stringToValue(), stringToNumber(), isDecimalNotation(), checkForInvalidNumberFormat() and getNumber() will be moved to a new class JSONUtil, since these static methods are called directly or indirectly by JSONObject, JSONArray, XML, and JSONML. The new methods will be marked protected, so that they cannot be called from user code. Config objects will be passed to stringToValue() when possible. When the method to be moved is public in an existing class, it will be marked as @deprecated instead of being deleted, and the code will be changed to use JSONUtil. Internal references to the public methods will be refactored to call JSONUtil instead.
No attempt will be made to check numbers which have already been added to a JSONObject or JSONArray (e.g. for getNumber() or optNumber())
PR #1065 (ab92bb9) addresses the long-digit-string case described in
this issue, but there is a second path to the same CWE-770 that the string.length() <= 1000 guard does not cover, so I don't think
CVE-2026-59171 is fully closed yet.
Remaining vector: short exponent literal + getBigInteger / optBigInteger
The length guard bounds the literal, not the magnitude. An
11-character literal like 1e100000000 passes the guard and is stored
cheaply as a BigDecimal (unscaled=1, scale=-100000000). The
expensive step happens later, when application code calls getBigInteger / optBigInteger:
same method, line 1425 (String path)
→ new BigDecimal(valStr).toBigInteger()
toBigInteger() then materialises a ~100 000 000-digit integer
(~40 MB, tens of seconds of CPU, or OutOfMemoryError). Reachable from JSONObject.getBigInteger/optBigInteger and JSONArray.getBigInteger/optBigInteger.
$ timeout 30 java -Xmx512m -cp target/classes:. Repro ; echo EXIT=$?
parsed: java.math.BigDecimal
EXIT=124 # killed after 30 s
Proposed fix — extend the same 1000-digit ceiling to the accessor
path, which is also the second half of the Jackson StreamReadConstraints
approach referenced above (maxBigIntegerScale):
if (valinstanceofBigDecimal) {
BigDecimalbd = (BigDecimal) val;
if ((long) bd.precision() - bd.scale() > 1000L) {
returndefaultValue;
}
returnbd.toBigInteger();
}
(precision()/scale() are O(1); same guard needed at line 1425.)
Happy to open a PR against this issue with the above plus a unit test
if that's the preferred workflow — let me know if you'd rather track
this as a separate issue.
@mechko Thanks, good catch, this is a valid related issue. You can open a PR, but there is a time and code contraint. All work should be completed before next Monday, and your code should be based on the max-number-length-config branch. If that works for you, feel free to open a PR.
Activity
stleary commentedon Jun 18, 2026
@waydeshi Thanks for submitting this issue, looks like a valid concern. If you have code to recreate the bug, please post it here.
waydeshi commentedon Jun 18, 2026
@stleary below is the PoC code.
POC Code
Actual Execution Output (Reproduced Against json-20260522.jar)
Executions:
javac -cp json-20260522.jar Poc2NumericDoSv2.java
java -cp .:json-20260522.jar Poc2NumericDoSv2
Key observations:
JSONObject,JSONArray,XML.toJSONObject) are equally affectedwithStrictMode(true)norwithKeepStrings(true)reduces the delaywaydeshi commentedon Jun 19, 2026
Hi @stleary have u got a chance to look into above PoC code and try?
Thx.
stleary commentedon Jun 19, 2026
Yes, the problem has been recreated and confirmed. Also found a related issue where using scientific notation for very large numbers results in an uncaught
NumberFormatException. Timeframe to fix both issues is about 2 weeks. Feel free to go ahead and create a CVE, if you wish.waydeshi commentedon Jun 20, 2026
Thank you for the confirmation. I will apply to reserve a CVE ID.
BTW, would you consider enabling the Security Advisory feature within this repo?
stleary commentedon Jun 20, 2026
Good idea, done.
waydeshi commentedon Jun 20, 2026
@stleary Thanks for the quick actions. I have raised a security advisory for this issue with all the details on my hand.
Please review and check there, modify it if you have any other suggestions about fix, etc.
After you patched this issue with a new release version, we could add it as the Patched versions within that security advisory and then publish it.
Finally Github Dependabot will automatically notify users who depend on JSON-java about this security advisory.
stleary commentedon Jun 21, 2026
Investigation notes:
Too-large exponential form (ex 1e999999999999) in a JSONObject or JSONArray:
NumberFormatException is thrown from static method
JSONObject.getNumber()Caught by static method
JSONObject.stringToNumber()Returned as an unconverted String.
This behavior goes back at least to 20210307. No changes planned at this time.
Too-long exponential form string is handled the same way, by returning the unconverted String.
Too-long non-negative natural number
Time-consuming call to new BigInteger() in static method
JSONObject.stringToNumber()Too-long decimal or negative natural number:
Time-consuming call to new BigDecimal() in static method
JSONObject.getNumber()The default and max number length properties will be stored in the base class ParserConfiguration.For now, this implementation will have a 1000-char fixed limit for parsing big numbers.
Max scientific notation conversions will have fixed max exponent value of +/-Math.pow(2, 32) i.e. about 2 billion.
Max digits in coefficient TBD
Invalid numeric values will be converted to String instead of throwing an exception, since this behavior is already in place for too-large exponential form. The JSONArray and XML parsers will have the same behavior. Note that the concern is for parsing text to JSON, not for retrieving values from a JSONObject or JSONArray.
The methodsobjectToBigInteger(),objectToBigDecimal(),stringToValue(),stringToNumber(),isDecimalNotation(),checkForInvalidNumberFormat()andgetNumber()will be moved to a new classJSONUtil, since these static methods are called directly or indirectly by JSONObject, JSONArray, XML, and JSONML. The new methods will be marked protected, so that they cannot be called from user code. Config objects will be passed tostringToValue()when possible. When the method to be moved is public in an existing class, it will be marked as @deprecated instead of being deleted, and the code will be changed to use JSONUtil. Internal references to the public methods will be refactored to call JSONUtil instead.No attempt will be made to check numbers which have already been added to a JSONObject or JSONArray (e.g. forgetNumber()oroptNumber())See #1066 For additional future work.
mechko commentedon Jul 13, 2026
Hi @stleary,
PR #1065 (ab92bb9) addresses the long-digit-string case described in
this issue, but there is a second path to the same CWE-770 that the
string.length() <= 1000guard does not cover, so I don't thinkCVE-2026-59171 is fully closed yet.
Remaining vector: short exponent literal +
getBigInteger/optBigIntegerThe length guard bounds the literal, not the magnitude. An
11-character literal like
1e100000000passes the guard and is storedcheaply as a
BigDecimal(unscaled=1, scale=-100000000). Theexpensive step happens later, when application code calls
getBigInteger/optBigInteger:JSONObject.objectToBigInteger,src/main/java/org/json/JSONObject.java:1402→
((BigDecimal) val).toBigInteger()→
new BigDecimal(valStr).toBigInteger()toBigInteger()then materialises a ~100 000 000-digit integer(~40 MB, tens of seconds of CPU, or
OutOfMemoryError). Reachable fromJSONObject.getBigInteger/optBigIntegerandJSONArray.getBigInteger/optBigInteger.Repro at current
master(1efb5f6, includes ab92bb9):Proposed fix — extend the same 1000-digit ceiling to the accessor
path, which is also the second half of the Jackson
StreamReadConstraintsapproach referenced above (
maxBigIntegerScale):(
precision()/scale()are O(1); same guard needed at line 1425.)Happy to open a PR against this issue with the above plus a unit test
if that's the preferred workflow — let me know if you'd rather track
this as a separate issue.
stleary commentedon Jul 13, 2026
@mechko Thanks, good catch, this is a valid related issue. You can open a PR, but there is a time and code contraint. All work should be completed before next Monday, and your code should be based on the
max-number-length-configbranch. If that works for you, feel free to open a PR.mechko commentedon Jul 14, 2026
@stleary Opened #1067 against
max-number-length-configwith theobjectToBigIntegerguard + unit test as discussed above.stleary#1063: add comment to expected-exception catch block (SonarClo…
stleary#1063: add JSONParserConfiguration overloads for getBigInteger…
#1063: bound BigDecimal->BigInteger expansion in objectToBigInteger
Merge pull request #1067 from mechko/1063-biginteger-exponent-dos
stleary commentedon Aug 27, 2026
Closing due to issue fixed in #1067