Gson, not JSON
Gson (Google JSON) is an open-source Java library developed by Google.
Its primary purpose is to convert Java objects into their JSON representation (serialization) and to convert a JSON string back into an equivalent Java object (deserialization).
How Gson Works
To understand Gson, think of it as a two-way bridge between your Java code and the JSON format.
- Serialization (
Object->JSON) If you have a Java object (e.g., aUserclass with a name and age), Gson reads that object’s fields and writes them into a JSON string.
Java: User user = new User("Ted", 21);
Gson Output: {"name":"Ted", "age":21}
- Deserialization (
JSON->Object)
When you receive data from an API or a file in JSON format, Gson maps those values back into a new instance of your Java class.
CVE History of Gson
In more than 17 years (since 2008), only one CVE has affected Gson.CVE-2022-25647: (Severity: High - CVSS 7.7)
Description: This is an insecure deserialization vulnerability affecting versions before
2.8.9.Technical Detail: The flaw exists in the
writeReplace()method in certain internal classes.
An attacker can craft a maliciousJSONpayload that, when processed, triggers this method to deserialize untrusted data.Impact: Primarily leads to Denial of Service (DoS) through resource exhaustion. While it is a deserialization flaw, it is generally not considered a Remote Code Execution (RCE) vector in standard configurations, though it can significantly disrupt application availability.
Mitigation: Upgrade to version
2.8.9or later.Fix: To address this, Google introduced a
NumberLimitsclass that imposes a strict limit of10,000characters for a numeric string.
If a number exceeds this limit, Gson is expected to throw an exception.
How to Bypass a CVE Fix: CVE-2022-25647

Incomplete fix?
Method: Identify the class or function that was modified by the fix.
Ask yourself: “Are there any other methods in this class (or in child classes) that manipulate the same sensitive data without calling the new protection mechanism?”
In our case, the fix protected intValue(), but overlooked its technical “siblings” (floatValue(), doubleValue()).
In short: “Don’t look at what the patch fixes; look at what it misses.”
In the security research community, you’ll also often hear variations like:
- “Focus on the delta, not the fix.”
- “Don’t analyze the solution; analyze the remaining attack surface.”
- “Attack the logic, not just the implementation.”
Vulnerability Description
The NumberLimits class was introduced in Gson to address CVE-2022-25647, a denial-of-service vulnerability caused by unbounded BigDecimal parsing of oversized numeric strings.
It enforces a hard cap of 10,000 characters on any number string before parsing:
NumberLimits.java
| |
This protection is correctly applied to intValue() and longValue() in LazilyParsedNumber, which route through asBigDecimal() and therefore through NumberLimits.
However, floatValue() and doubleValue() call Float.parseFloat() and Double.parseDouble() directly, with no length check:
LazilyParsedNumber.java- lines 67-74
| |
LazilyParsedNumber is the default representation for any field of type Number (not a float/double primitive) deserialized by Gson.
This is the default strategy, LAZILY_PARSED_NUMBER, configured in GsonBuilder at line 107:
GsonBuilder.java:107
| |
This means the bypass is reachable with zero configuration, against any Gson-based application that deserializes a field typed as Number and subsequently calls floatValue() or doubleValue() on it.
Proof of Concept
Requirements:
- Java 11+ (JRE only)
- Gson source:
git clone https://github.com/google/gson.git - Maven:
mvn package -DskipTestsFor this setup, I installed Maven using this guide, with the latest Maven version (3.9.12) available here.
| |
Poc2.javafile
| |
Output
| |
Timeline of What Happened
I reported the issue on Feb 15, 2026. It was eventually accepted on Mar 10, 2026, but only after multiple close/reopen cycles.

If I had not pushed back, the issue likely would have stayed out of scope despite being valid.

Finally they accept the bug

A few weeks later, the report was accepted without a full fix because the remaining work was considered too time-consuming.
I still kept the reward and my ranking in the Hall of Fame and leaderboard.

Status Timeline
- Feb 15, 2026 (13:42): Report closed.
- Feb 16, 2026 (14:32): Report triaged (reopened).
- Mar 5, 2026 (21:53): Report closed again.
- Mar 6, 2026 (08:10): Report triaged again.
- Mar 6, 2026 (23:48): Report closed again.
- Mar 10, 2026 (08:56): Report triaged again.
- Mar 10, 2026 (14:27): Report accepted.
- Apr 3, 2026 (03:45): Report closed.










































































































