RMI Methods Accepting Serializable Objects
Defining RMI interface methods that accept Serializable or Object parameters.
RMI deserialization vulnerabilities occur when RMI methods accept arbitrary Serializable objects as parameters. Attackers can send malicious serialized objects containing gadget chains that execute arbitrary code during deserialization. RMI services are particularly vulnerable because they automatically deserialize method parameters over the network.
import java.rmi.*;
import java.io.Serializable;
// VULNERABLE: RMI interface accepts arbitrary objects
public interface DataService extends Remote {
// DANGEROUS: accepts any Serializable object
String processData(Serializable data) throws RemoteException;
// DANGEROUS: accepts Object directly
Object executeTask(Object task) throws RemoteException;
}
// Implementation
public class DataServiceImpl implements DataService {
@Override
public String processData(Serializable data) throws RemoteException {
// VULNERABLE: data could be malicious gadget chain
if (data instanceof String) {
return "Processed: " + data;
} else if (data instanceof UserData) {
return processUserData((UserData) data);
}
return "Unknown type";
}
@Override
public Object executeTask(Object task) throws RemoteException {
// Extremely dangerous - accepts any object
return "Task executed";
}
}
// Attacker can send gadget chain payload using tools like ysoserialimport java.rmi.*;
// SECURE: RMI interface uses primitives and IDs
public interface SecureDataService extends Remote {
// SAFE: uses primitive types and strings
String processDataById(long dataId) throws RemoteException;
// SAFE: uses JSON string instead of objects
String submitTask(String taskType, String jsonParams)
throws RemoteException;
// SAFE: returns status by ID
String getTaskStatus(long taskId) throws RemoteException;
}
// Secure implementation
public class SecureDataServiceImpl implements SecureDataService {
private final DataRepository repository;
private final ObjectMapper jsonMapper;
public SecureDataServiceImpl() throws RemoteException {
this.repository = new DataRepository();
this.jsonMapper = new ObjectMapper();
// Enable JEP 290 deserialization filter
System.setProperty("jdk.serialFilter",
"java.lang.String;java.lang.Number;!*");
}
@Override
public String processDataById(long dataId) throws RemoteException {
// Load data server-side using ID - no deserialization of user objects
Object data = repository.findById(dataId);
return processDataSecurely(data);
}
@Override
public String submitTask(String taskType, String jsonParams)
throws RemoteException {
// Validate task type
if (!isValidTaskType(taskType)) {
throw new RemoteException("Invalid task type");
}
// Safe JSON deserialization to simple DTO
TaskParamsDTO params = jsonMapper.readValue(
jsonParams, TaskParamsDTO.class);
return taskService.createTask(taskType, params);
}
@Override
public String getTaskStatus(long taskId) throws RemoteException {
return taskService.getStatus(taskId).toString();
}
}The vulnerable code accepts Serializable and Object parameters in RMI methods, allowing attackers to send malicious gadget chains that execute code during deserialization. The secure version uses only primitive types, strings, and IDs as parameters, loading data server-side and using JSON for complex data transfer.
Defining RMI interface methods that accept Serializable or Object parameters.
Sourcery automatically identifies remote code execution via java rmi object deserialization and many other security issues in your codebase.