Safeguard
DevSecOps

org.json Maven: A Security Guide

The org.json Maven dependency ships a small JSON parser with a history of denial-of-service bugs. Here is how to pin a safe version and catch it transitively.

Priya Mehta
DevSecOps Engineer
6 min read

The org.json Maven artifact (org.json:json) is safe to use if you pin version 20231013 or later; older releases carry two documented denial-of-service vulnerabilities that are easy to reach from untrusted input. It is one of the most widely pulled JSON libraries on Maven Central, usually arriving as a transitive dependency rather than something you added by hand, which is exactly why teams get caught on an old version.

This guide covers what the library is, the vulnerabilities that have shipped in it, the coordinate you should declare, and how to find a stale copy hiding several levels down your dependency tree.

What org.json actually is

The Maven org.json coordinate is:

<dependency>
  <groupId>org.json</groupId>
  <artifactId>json</artifactId>
  <version>20231013</version>
</dependency>

This is the reference implementation of JSON in Java, originally written by Douglas Crockford and now maintained by the stleary/JSON-java project on GitHub. The versioning is unusual: instead of semantic versions, releases are dated (20231013 means the release from 13 October 2023). That trips people up because a "higher" number is simply a later date, and there is no major/minor signal about breaking changes.

Because so many older libraries and internal tools depend on it, a maven org.json entry frequently appears in your build even when your own pom.xml never names it. That transitivity is the root of most exposure.

The vulnerabilities you need to know about

Two CVEs matter here, both denial-of-service class, both reachable when your service parses attacker-controlled JSON or XML.

CVE-2022-45688 is a stack overflow in the XML.toJSONObject path. Deeply nested XML or JSON causes unbounded recursion and crashes the thread with a StackOverflowError. It affects org.json:json before version 20230227 and is rated HIGH (CVSS 7.5). If your code converts XML to JSON with this library on a request path, a small crafted payload can take the worker down.

CVE-2023-5072 is a separate denial-of-service bug affecting versions up to and including 20230618. A specially crafted JSON string with embedded null characters is mishandled by the parser, and escaping causes the string length to grow exponentially until the JVM throws an OutOfMemoryError. This one is fixed in version 20231013.

Note the sequencing: 20230227 fixes the first bug but is still vulnerable to the second. Only 20231013 (or later) clears both. Version 20231013 was also the first release to raise the minimum Java baseline to Java 8, so a small number of legacy Java 6/7 builds may need a compatibility check before bumping.

If you cannot find your exact version in this text, do not assume; check your resolved tree (below) against the advisories on the NVD and the project's own release notes rather than guessing.

Finding a vulnerable org.json:json in your tree

The json maven artifact is almost always transitive, so grepping your pom.xml will miss it. Ask Maven what actually resolved:

mvn dependency:tree -Dincludes=org.json:json

That prints every path that pulls the library in and the version each path requested. On a real service you often see two or three different versions requested by different libraries, with Maven's "nearest wins" rule picking one. For Gradle the equivalent is:

./gradlew dependencyInsight --dependency org.json:json

Once you know where it comes from, you have three moves depending on whether you own the dependency.

Pinning a safe version

If your project declares org.json directly, just set the version to 20231013 or newer.

When the vulnerable copy arrives transitively, force the resolved version without adding a runtime dependency you do not want. In Maven, use dependencyManagement:

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.json</groupId>
      <artifactId>json</artifactId>
      <version>20231013</version>
    </dependency>
  </dependencies>
</dependencyManagement>

This pins the version anywhere in the tree without declaring a new compile dependency. In Gradle, a resolution strategy does the same job:

configurations.all {
  resolutionStrategy {
    force 'org.json:json:20231013'
  }
}

Rebuild, rerun dependency:tree, and confirm the version you see is the one you forced. Forcing without verifying is how "fixed" tickets reopen three months later.

Reducing the blast radius in code

Pinning removes the known CVEs, but the underlying risk pattern is worth defending against directly: any parser that recurses on nested input can be pushed over by hostile depth or size. A few habits reduce the attack surface regardless of library version.

Cap the size of request bodies before they reach a parser. A JSON payload has no business being tens of megabytes on most APIs, and a hard limit at the framework layer neutralizes the amplification pattern behind CVE-2023-5072. If you convert XML to JSON, question whether you need that conversion on an untrusted path at all; the XML surface is where CVE-2022-45688 lives.

For services that parse a lot of third-party JSON, some teams move to a streaming parser such as Jackson with a configured StreamReadConstraints (maximum nesting depth and string length), which fails fast on pathological input instead of exhausting memory. That is a bigger change than a version bump, so treat it as a follow-up rather than the fix.

Keeping it from coming back

A one-time bump does not hold. New transitive paths appear every time you upgrade an unrelated library, and one of them can quietly reintroduce an old org.json. The durable fix is a check in continuous integration that fails the build when a known-vulnerable version resolves.

Software composition analysis tooling reads your resolved dependency graph rather than your declared manifest, so it sees the transitive org.json copy that a manual review misses. An SCA tool such as Safeguard can flag a vulnerable org.json:json even when it sits four levels down under a library you have never heard of, and map it to the CVE and the fixed version. If you want the background on how that graph analysis works, our SCA product page walks through it, and the Jackson databind security guide covers the same transitive pattern for the other big Java JSON library.

FAQ

What is the latest safe org.json Maven version?

Pin 20231013 or later. That release fixed CVE-2023-5072 and already contained the earlier fix for CVE-2022-45688. Check Maven Central for the newest dated release before you settle on a number.

Why does org.json use dates instead of semantic versions?

The stleary/JSON-java project releases on a rolling schedule and tags each release by date (yyyymmdd). A larger number is simply a more recent release; it carries no major/minor compatibility promise, so read the release notes before bumping across the 20231013 Java 8 baseline change.

Is org.json vulnerable if I only produce JSON and never parse untrusted input?

The two documented CVEs are denial-of-service bugs triggered by parsing crafted input. If you only serialize your own objects and never parse attacker-controlled JSON or XML, the practical risk is low, but you should still pin a fixed version so a future code change on a request path does not reintroduce the exposure.

How do I find org.json if it is not in my pom.xml?

Run mvn dependency:tree -Dincludes=org.json:json (or gradlew dependencyInsight --dependency org.json:json). It resolves the full graph and shows every transitive path that pulls the library in, which is where most vulnerable copies hide.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.