Skip to main content
VulnerabilityPublished

CVE-2026-59171: JSON-java · JSONTokener Has Unbounded Numeric String Resource-Exhaustion DoS

Affects org.json:jsonSource GCVE Database

0
Compare

Mentioned vulnerabilities

Authoritative record:CVE-2026-59171· Medium 5.9

Not known to be exploited · CVSS 5.9 Medium : upgrade to 20260719 when convenient.

Data as of 9 Nov 2026, 23:24 UTC

CVSS 3.1 base score
5.9Medium
How severe the flaw is on the 0–10 CVSS scale.

Thin evidence

One scorer or none
CVSS scores by source
CNA (GitHub_M)CVSS 3.15.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:H

Exploitation evidence

  1. Disclosed: evidence found.

    CVE published 6 Nov 2026

  2. Detectable: no evidence on record.

    No public nuclei template indexed

  3. Weaponized: no evidence on record.

    No public exploit code indexed in Metasploit or Exploit-DB

  4. Exploited in the wild: no evidence on record.

    Not in CISA KEV and no source reports exploitation

  5. Observed by OffSeq 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

ProductAffectedFixed in
Mavenorg.json:jsonAffected
  • >=20150729 <20260719
Fixed in
  • 20260719

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

Community reviews

Loading reviews…