CVE-2026-59171: JSON-java · JSONTokener Has Unbounded Numeric String Resource-Exhaustion DoS
Affects org.json:jsonSource GCVE Database
Mentioned vulnerabilities
Not known to be exploited · CVSS 5.9 Medium : upgrade to 20260719 when convenient.
Data as of 9 Nov 2026, 23:24 UTC
Thin evidence
One scorer or none| CNA (GitHub_M) | CVSS 3.1 | 5.9 |
|---|
- EPSS
- 0.5% chance of exploitation in 30 days – higher than 46% of CVEsExploit Prediction Scoring System: the likelihood attackers will use this flaw soon.
- Patch
- Available – fixed in 20260719
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:HExploitation evidence
Disclosed: evidence found.
CVE published 6 Nov 2026
Detectable: no evidence on record.
No public nuclei template indexed
Weaponized: no evidence on record.
No public exploit code indexed in Metasploit or Exploit-DB
Exploited in the wildExploited: no evidence on record.
Not in CISA KEV and no source reports exploitation
Observed by OffSeq MirageSeen by Mirage: no evidence on record.
No attack traffic recorded by OffSeq Mirage sensors
A missing step is not evidence of safety. Sources: cve.org (opens in a new tab), the Metasploit, Exploit-DB and nuclei-templates index as of 9 Nov 2026.
What to do
Upgrade org.json:json to 20260719.
Affected software
| Product | Affected | Fixed in |
|---|---|---|
| Mavenorg.json:json | Affected
| Fixed in
|
Check your own hosts for these packages with threat-finder (opens in a new tab), our free open-source scanner.
Description
## 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. --- ## 2. Vulnerability Description `JSONTokener.nextSimpleValue()` accumulates characters into a `StringBuilder` with no length limit until it hits a structural JSON character: **`JSONTokener.java:500–504`:** ```java StringBuilder sb = new StringBuilder(); while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) { sb.append(c); // unbounded — no length check c = this.next(); } ``` The accumulated string is passed to `JSONObject.stringToValue()` → `stringToNumber()`, which calls `new BigInteger(val)` with zero size guard: **`JSONObject.java:2738`:** ```java BigInteger bi = new BigInteger(val); // val can be arbitrarily large; no guard ``` `BigInteger(String)` has O(n^1.585) time complexity due to its internal Karatsuba multiplication during construction. A 100,000-digit input takes ~120 ms; a 1,000,000-digit input takes ~12 seconds. The decimal path (`new BigDecimal(val)`, reached when the string contains a `.` or exponent) is equally affected. **No configuration option prevents this.** `withStrictMode(true)` and `withKeepStrings(true)` are not checked in the `nextSimpleValue()` → `stringToNumber()` call chain. Confirmed by execution: both options still produce BigInteger in ~120 ms for a 100K-digit input. **Relationship to CVE-2023-5072:** CVE-2023-5072 (fixed in release 20231013) catches `StackOverflowError` thrown by deeply nested JSON *structures* (`{[` brackets) inside `nextValue()`: ```java } catch (StackOverflowError e) { throw new JSONException("JSON Array or Object depth too large to process.", e); } ``` This fix is in `nextValue()` and covers only recursive object/array structure depth. It has no effect on the numeric string length path in `nextSimpleValue()` → `stringToNumber()`. The BigInteger length issue was not addressed in 20231013 or in any subsequent release. --- ## 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 | --- ## 4. Proof of Concept (Locally Verified) ### 4.1 POC Code ```java import org.json.*; public class Poc2NumericDoSv2 { public static void main(String[] args) { System.out.println("=== CVE-002: JSONTokener Unbounded Numeric String DoS ==="); // Scaling: timing at different digit counts System.out.println("\n-- Unquoted numeric literal (JSONObject) --"); int[] sizes = {10_000, 100_000, 200_000, 500_000, 1_000_000}; for (int numLen : sizes) { String payload = "{\"x\":" + "9".repeat(numLen) + "}"; long start = System.currentTimeMillis(); JSONObject jo = new JSONObject(payload); long elapsed = System.currentTimeMillis() - start; System.out.printf(" %,7d digits (~%3d KB): %,5d ms type=%s%n", numLen, payload.length()/1024, elap
References
- github.com/stleary/JSON-java/security/advisories/GHSA-ghc9-756g-vrcv (opens in a new tab)
- nvd.nist.gov/vuln/detail/CVE-2026-59171 (opens in a new tab)
- github.com/stleary/JSON-java/pull/1065 (opens in a new tab)
- github.com/stleary/JSON-java/pull/1067 (opens in a new tab)
- github.com/stleary/JSON-java/commit/703ac34a55400f9c50889e3d0c778b6d7962e81c (opens in a new tab)
- github.com/stleary/JSON-java/commit/ab92bb9088a37f9e346cd1dda66f6a3c40a201e0 (opens in a new tab)
- github.com/stleary/JSON-java/commit/fce83c91bb229dde472283dea648a9a8955237fd (opens in a new tab)
- github.com/stleary/JSON-java (opens in a new tab)
- github.com/stleary/JSON-java/releases/tag/20260719 (opens in a new tab)