I tried the following experiment (this is just a pseudocode):
class Server {
    public static void main(final String args[]) {
        final ServerSocket server = new ServerSocket(PORT);
        final Socket client = server.accept();
        final ObjectInputStream stream = new ObjectInputStream(client.getInputStream());
        final Object object = stream.readObject();
        // Can we hope that standard toString method will be called?
        System.out.println(object.toString());
    }
}
then created a malicious object:
class MaliciousObject extends Object implements Serializable {
    private static final long serialVersionUID = 1L;
    @Override
    public String toString() {
        return "I am malicious object";
    }
}
and finally sent an instance of malicious object to the sever using another program:
public static void main(final String args[]) {
    final Socket socket = new Socket();
    socket.connect(serversAddress, TIMEOUT);
    final ObjectOutputStream stream = new ObjectOutputStream(socket.getOutputStream());
    stream.writeObject(new MaliciousObject());
}
The output that Server printed to the screen was
I am malicious object
So it seems that a hacker can implement a class extending object, override any method M to execute some malicious code, then send this object over the network in a hope that server will call M.
Hence, my question is: how to defend against this? If we read objects from ObjectInputStream, how can we be sure that they're not malformed?
As a side question, is in this case Java class loader involved when reading objects from ObjectInputStream?
 
     
     
    