Remote Code Execution from Untrusted Java Object Deserialization

Critical Risk Deserialization & Object Security
javadeserializationrceobjectinputstreamgadget-chains

What it is

Remote code execution (RCE) vulnerability where code deserializes attacker-controlled bytes with ObjectInputStream without strict type filtering or authentication, enabling gadget chains during object reconstruction. Java deserialization is particularly dangerous because attackers can leverage existing classes in the application's classpath to construct gadget chains that execute arbitrary code during the deserialization process.

import java.io.*;
import org.springframework.web.bind.annotation.*;

@RestController
public class DataController {
    
    // VULNERABLE: deserializes untrusted input
    @PostMapping("/api/data/import")
    public String importData(@RequestBody byte[] data) {
        try {
            ByteArrayInputStream bis = new ByteArrayInputStream(data);
            ObjectInputStream ois = new ObjectInputStream(bis);
            
            // DANGEROUS: executes gadget chains
            Object obj = ois.readObject();
            
            return "Data imported";
        } catch (Exception e) {
            return "Import failed";
        }
    }
}
import java.io.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.web.bind.annotation.*;

@RestController
public class DataController {
    
    private final ObjectMapper jsonMapper = new ObjectMapper();
    
    // SECURE: use JSON instead of Java serialization
    @PostMapping("/api/data/import")
    public String importData(@RequestBody String jsonData) {
        try {
            // Safe: JSON deserialization to known DTO
            UserDataDTO userData = jsonMapper.readValue(
                jsonData, UserDataDTO.class);
            
            // Validate before processing
            if (userData.isValid()) {
                processData(userData);
                return "Data imported";
            }
            return "Invalid data";
        } catch (Exception e) {
            return "Import failed";
        }
    }
}

💡 Why This Fix Works

The vulnerable code uses ObjectInputStream.readObject() on untrusted data, allowing attackers to execute arbitrary code via gadget chains. The secure version uses JSON deserialization which only constructs simple data objects without executing code, and validates the data before processing.

Why it happens

Using ObjectInputStream.readObject() on data from HTTP requests, sockets, or files without validation.

Root causes

Deserializing Untrusted Data Without Filtering

Using ObjectInputStream.readObject() on data from HTTP requests, sockets, or files without validation.

Missing ObjectInputFilter

Not implementing ObjectInputFilter to restrict which classes can be deserialized.

Dangerous Libraries in Classpath

Having libraries like Apache Commons Collections that enable gadget chain attacks.

Fixes

1

Use Safe Data Formats

Replace Java serialization with JSON, XML, or Protocol Buffers which don't execute code.

2

Implement ObjectInputFilter

Use ObjectInputFilter with strict allowlists to control which classes can be deserialized.

3

Authenticate Serialized Data

Use HMAC to verify data integrity before deserialization.

Detect This Vulnerability in Your Code

Sourcery automatically identifies remote code execution from untrusted java object deserialization and many other security issues in your codebase.