Back to results for “I/O & NIO”
Java › I/O & NIO

Why has Java's built-in serialization (ObjectInputStream.readObject()) been widely criticized as a security risk, and what specific attack does deserializing untrusted data enable?

Advanced

Answer

Java's built-in deserialization mechanism, by its very design, reconstructs arbitrary object graphs directly from byte data, including invoking constructors and potentially triggering arbitrary code execution through crafted 'gadget chains' (sequences of otherwise-innocuous method calls across classes already present on the classpath that, when triggered in a specific unintended sequence during deserialization, can be chained together to achieve arbitrary code execution) -- deserializing data from an untrusted source (like unauthenticated network input) using readObject() has historically been the root cause of numerous serious, widely-exploited real-world vulnerabilities, which is why current best practice strongly discourages using Java's native serialization for any data crossing a trust boundary, favoring safer, more restrictive alternatives like JSON (via a library configured to avoid polymorphic type deserialization vulnerabilities) or Protocol Buffers instead.
// DANGEROUS: deserializing untrusted input directly
public Object deserializeUntrusted(byte[] untrustedData) throws Exception {
    try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(untrustedData))) {
        return in.readObject();  // could trigger a gadget-chain exploit if the byte data is maliciously crafted
    }
}

// SAFER: use a restrictive JSON library with explicit type allowlisting instead of native Java serialization
// for any data originating from outside the trust boundary
Real-world example A security audit flags a service that deserializes untrusted network input using ObjectInputStream.readObject() directly as a critical vulnerability, referencing well-documented gadget-chain exploits (like the widely-publicized Apache Commons Collections deserialization vulnerability) that allowed remote code execution against similarly-configured applications, prompting a migration to JSON-based serialization with strict type validation instead.

Common follow-ups: What is a 'gadget chain' specifically, and why does simply having certain libraries on the classpath create risk even if your own code never intentionally uses them for this purpose?;What mitigations exist if native Java serialization genuinely must be used (like ObjectInputFilter)?