Vulnerability GHSA-ghc9-756g-vrcv

Medium Risk
MEDIUM RISK
CVSS Score: 5.9
Score Range: 4.0–6.9
Medium severity vulnerabilities (CVSS 4.0–6.9). Important issues that meaningfully reduce security confidence.
7 hours ago
November 09, 2026 at 09:12 PM UTC
JSON-java: JSONTokener Has Unbounded Numeric String Resource-Exhaustion DoS
20150729 and 20151123 and 20160212 and 20160807 and 20160810 and 20170516 and 20171018 and 20180130 and 20180813 and 20190722 and 20200518 and 20201115 and 20210307 and 20211205 and 20220320 and 20220924 and 20230227 and 20230618 and 20231013 and 20240205 and 20240303 and 20241224 and 20250107 and 20250517 and 20251224 and 20260522
20150729 and 20151123 and 20160212 and 20160807 and 20160810 and 20170516 and 20171018 and 20180130 and 20180813 and 20190722 and 20200518 and 20201115 and 20210307 and 20211205 and 20220320 and 20220924 and 20230227 and 20230618 and 20231013 and 20240205 and 20240303 and 20241224 and 20250107 and 20250517 and 20251224 and 20260522

Summary

JSON-java: JSONTokener Has Unbounded Numeric String Resource-Exhaustion DoS

Details

1. Executive Summary

JSON-java version 20260522 contains an unguarded path from an HTTP request body to unbounded BigInteger and BigDecimal construction. JSONTokener.nextSimpleValue() accumulates numeric characters into a StringBuilder with no length cap, then passes the full string to JSONObject.stringToNumber(), which calls new BigInteger(val) or new BigDecimal(val) directly. Both constructors have polynomial time complexity (O(n^1.585) for BigInteger).

A 488 KB JSON body — well within nginx's default 1 MB body-size limit — contains a 500,000-digit numeric literal that blocks the handling thread for approximately 3 seconds. Spring Boot has no default size limit for application/json request bodies. No parser configuration option (withStrictMode, withKeepStrings) prevents this. All three primary entry points are affected: new JSONObject(String), new JSONArray(String), and XML.toJSONObject(String).

This vulnerability is distinct from CVE-2023-5072 (which addressed StackOverflowError from deeply nested JSON structures via a try/catch in nextValue()) and from CVE-2022-45688 (which addressed recursive XML nesting depth). The numeric string length issue has been present since BigInteger support was introduced in release 20150729 and has never been fixed in any subsequent release.

Attack Complexity is rated High because successful exploitation requires the target application to be using org.json specifically (rather than the default Jackson library used by Spring Boot), and requires the developer to have explicitly passed user-controlled input to new JSONObject() or equivalent. These are deployment conditions beyond the attacker's control. See Section 6 for the full CVSS rationale and Section 8 for the comparison with Jackson's treatment of the same issue class.

This vulnerability was reproduced locally against json-20260522.jar with full evidence provided below.

3. Affected Code Locations

File Lines Description
JSONTokener.java 500–504 nextSimpleValue() — unbounded character accumulation into StringBuilder, no length cap
JSONObject.java 2721–2748 stringToNumber() — new BigInteger(val) / new BigDecimal(val) called directly with no length guard

5. Attack Scenarios

5.1 Thread-Pool Exhaustion via Concurrent Requests

A Java web application that explicitly uses org.json for request body parsing exposes a JSON endpoint. The developer parses the request body with new JSONObject(requestBody).

Single attack request:

POST /api/order HTTP/1.1
Host: target.example.com
Content-Type: application/json
Content-Length: 500011

{"amount":999...999}   (500,000 nines — ~488 KB body)

Effect: This single request occupies one Tomcat thread for ~3 seconds. To exhaust a default 200-thread Tomcat pool, the attacker sends 200 concurrent such requests — a total of ~95 MB of concurrent traffic (200 × 488 KB), achievable with any standard load-generation tool (ab, wrk, hey). While those threads are occupied, legitimate user requests queue and time out.

Why common defaults do not prevent this:

  • nginx default client_max_body_size = 1 MB → 488 KB payload passes through
  • Spring Boot has no default size limit for application/json @RequestBody (Tomcat's maxPostSize applies only to application/x-www-form-urlencoded and multipart/form-data, not to JSON)
  • No configuration option within org.json itself provides any protection

5.2 Amplification Ratio

The blocking time grows super-linearly with payload size, creating an asymmetric attack:

Payload size Thread blockage Ratio (ms per KB sent)
9 KB (10K digits) 17 ms 1.9 ms/KB
97 KB (100K digits) 123 ms 1.3 ms/KB
195 KB (200K digits) 479 ms 2.5 ms/KB
488 KB (500K digits) ~2,975 ms 6.1 ms/KB
976 KB (1M digits) ~11,909 ms 12.2 ms/KB

A 488 KB request — well within nginx's 1 MB default — ties up a server thread for 3 seconds. The ratio of CPU time consumed to bytes sent grows with payload size due to Karatsuba's super-linear complexity.

5.3 All Primary Entry Points Are Affected

The vulnerability is not limited to new JSONObject(String). Any org.json parsing call on the same numeric input produces the same delay:

new JSONObject(String):     121 ms  (for 100K digits)
new JSONArray(String):      120 ms  (for 100K digits)
XML.toJSONObject(String):   123 ms  (for 100K digits)

Any endpoint that parses user-controlled JSON or XML through org.json is a potential target, regardless of which specific API method is used.

8. Comparison with Jackson's Treatment of the Same Issue

Jackson 2.15.0 (released April 2023) introduced StreamReadConstraints.withMaxNumberLength() with a default limit of 1,000 digits to address this exact class of vulnerability — and did so without a CVE being filed. This raises a legitimate question: if the Jackson ecosystem handled the same issue without a CVE, why does org.json warrant one?

The two situations are materially different in three ways:

1. Jackson's fix was universal and automatic; org.json's omission is not.

Jackson is the default JSON library in Spring Boot. When Jackson 2.15 shipped with DEFAULT_MAX_NUM_LEN = 1000, the protection was automatically applied to the entire Spring Boot ecosystem without any developer action. Every Spring Boot application upgrading to Spring Boot 3.1+ received the protection transparently.

org.json has no equivalent protection in any version through 20260522. Applications using org.json receive no protection from any upstream fix and have no configurable option to enable it. There is no automatic upgrade path.

2. org.json has an established CVE precedent for the same DoS class.

This project has already been assigned CVEs for resource-exhaustion vulnerabilities triggered by crafted parsing input:

  • CVE-2022-45688: XML recursive nesting DoS
  • CVE-2023-5072: JSON nested {[ structure DoS

Both were assigned under the same root pattern: parser accepts unbounded user-controlled input, resulting in resource exhaustion. The numeric string length issue is the same pattern in the same library, in a code path that the two prior fixes explicitly left unaddressed. Treating this as a non-CVE while the two structurally identical prior issues were assigned CVEs would be inconsistent.

3. RFC 8259 explicitly permits — and implicitly recommends — setting limits on number length.

RFC 8259 §6 states: "This specification allows implementations to set limits on the range and precision of numbers accepted." The RFC anticipates that secure implementations will impose such limits. org.json's NOTES.md acknowledges only "partial support" for BigInteger/BigDecimal, but provides no size guard and no documentation warning users of the DoS risk. The absence of a documented security boundary in the presence of an RFC-permitted and industry-standard protection mechanism constitutes an exploitable implementation deficiency.

Impacted packages

Timeline

Published
7 hours ago
November 09, 2026 at 09:12 PM UTC
Fixed (20260719)
Unknown
Unknown
Last Modified
6 hours ago
November 09, 2026 at 09:30 PM UTC