- changed status to open
Parsing must reject deeply nested JSON objects and arrays
Attempting to serialize a deeply nested map structure in a JWTClaimsSet causes a StackOverflowError due to excessive recursion in Gson’s serialization process. A claim set like this could be supplied by a client, parsed and logged, causing SOE.
Reproduction
import com.nimbusds.jwt.JWTClaimsSet;
import java.text.ParseException;
import java.util.HashMap;
import java.util.Map;
public class Test {
// This builds a claimset with a deeply nested map, which could theoretically be supplied by a client.
// If the JWT is serialized into JSON (for example, in logging or debugging), it can cause a StackOverflowError.
public static void main(String[] args) throws ParseException {
Map<String, Object> nestedMap = new HashMap<>();
Map<String, Object> currentLevel = nestedMap;
for (int i = 0; i < 5000; i++) {
Map<String, Object> nextLevel = new HashMap<>();
currentLevel.put("", nextLevel);
currentLevel = nextLevel;
}
JWTClaimsSet claimSet = JWTClaimsSet.parse(nestedMap);
// This will cause a StackOverflowError due to excessive recursion in GSON's serialization
claimSet.toString();
}
}
Comments (9)
-
-
Any updates on this issue?
-
The current plan is to create a
custom com.google.gson.JsonDeserializer
and let it check the JSON object nesting depth, before calling the actual Gsondeserialize
.The
JWTClaimsSet
parse
andtoJSONobject
methods don't throw aStackOverflowError
under the same condition. Only thetoString
which calls the Gsondeserialize
appears affected. -
Hey all,
I just came across this issue because our dependency management alerted me to a potential DoS vulnerability in Google gson.
I’ve dug into the issue a bit, and it seems all you’d need to do is update gson to >= 2.12.0.
They’ve found the problem via fuzzing and implemented a default nesting limit of 255.
Add nesting limit for `JsonReader` by Marcono1234 · Pull Request #2588 · google/gson · GitHub
Cheers,
Daniel
-
Thanks Daniel for the tip!
-
Our testing with Gson 2.12.1 shows that the
toString()
continues to throw aStackOverflowError
.Gson 2.12 changes the parsing to reject nesting deeper than 255, not the serialization. The upgrade to Gson 2.12.1 should still address the original concern though, to prevent parsing of such JSON in the first place.
public void testSerializationWithDeepJSONObjectNestingCausesStackOverflowError() { Map<String, Object> jsonObject = JSONObjectUtils.newJSONObject(); Map<String, Object> ref = jsonObject; for (int i=0; i < 20_000; i++) { Map<String, Object> nested = JSONObjectUtils.newJSONObject(); ref.put("a", nested); ref = nested; } JWTClaimsSet claimsSet = new JWTClaimsSet.Builder() .claim("o", jsonObject) .build(); try { claimsSet.toString(); fail(); } catch (StackOverflowError e) { assertNull(e.getMessage()); } }
-
- changed title to Parsing must reject deeply nested JSON objects and arrays
- removed milestone
Changes the title to reflect the actual fix.
-
- changed status to resolved
Marking as resolved with:
10.0.2 (2025-02-25) * Updates JSONObjectUtils.parse and JSONArrayUtils.parse to reject JSON strings with object and array nesting deeper than 255. This change is the default parse behaviour of GSon 2.12.0+ (iss #583) * Updates GSon to 2.12.1.
Updated tests and Gson bump to 2.12.2: 393a96f
-
Oh your right, I missed the serialization part
Awesome! Thanks for the quick fix :)
- Log in to comment