Skip to content

Potentially unsafe deserialization in JSONObject#fromJson() static fields are not excluded #1043

@yuki-matsuhashi

Description

@yuki-matsuhashi

This behavior may be security-relevant when JSONObject#fromJson(Class<T>) is used on untrusted input, so I am reporting it here as a public issue in line with the repository's published vulnerability-reporting guidance.

In release 20251224, JSONObject#fromJson(Class<T>) iterates clazz.getDeclaredFields(), calls Field#setAccessible(true), and assigns matching JSON values without excluding static fields:

public <T> T fromJson(Class<T> clazz) {
try {
T obj = clazz.getDeclaredConstructor().newInstance();
for (Field field : clazz.getDeclaredFields()) {
field.setAccessible(true);
String fieldName = field.getName();
if (has(fieldName)) {
Object value = get(fieldName);
Type fieldType = field.getGenericType();
Object convertedValue = convertValue(value, fieldType);
field.set(obj, convertedValue);
}
}
return obj;

As a result, deserialization can write not only per-instance state but also mutable declared class-level state on the caller-selected target type, subject to normal runtime access restrictions. That expands the binding surface beyond ordinary object population and may have integrity implications in applications that use fromJson() with untrusted JSON.

If helpful, I can provide a minimal reproducer and a regression test. A straightforward mitigation appears to be skipping static fields during binding.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions