BackendBench
Coffee

Unravel › Java concepts › I/O and files

I/O and data

Java serialization and its risks

Java can turn an object graph into bytes (Serializable) and back.

🔎 Unravel this example

At a glance

Mental model

Flat-pack furniture with instructions in your own language.

What happens, in order
  1. 1A class implementing Serializable can be written with ObjectOutputStream.writeObject(obj) and read with ObjectInputStream.readObject()All fields are saved except transient and static ones.
  2. 2serialVersionUID identifies the class versionIf it changes (or is missing and the class changes), reading old bytes throws InvalidClassException.
  3. 3Hooks readObject, writeObject, readResolve customise the process (for example re-creating a singleton or validating state)
  4. 4HTTP sessions in a cluster, caches (Redis with the JDK serializer), and JMS ObjectMessage often use it behind the scenes
Remember
Watch out
Deserializing untrusted inputMissing or changing serialVersionUID unintentionallyStoring Java-serialized data long-termNon-transient fields holding resources
Example (highlighted lines explain it)
ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes));in.setObjectInputFilter(ObjectInputFilter.Config.createFilter("com.shop.model.*;!*"));Object value = in.readObject();
  1. line 1 uses ObjectInputStream, the core of Java serialization and its risks
  2. line 2 uses ObjectInputFilter, the core of Java serialization and its risks
  3. line 3 uses readObject, the core of Java serialization and its risks
Read the full explanation (about 2 min)

Java can turn an object graph into bytes (Serializable) and back. It is convenient and built into old frameworks (sessions, RMI, JMS object messages), but it is fragile across versions and a classic source of remote code execution.

A mental model

Flat-pack furniture with instructions in your own language. Fine between two identical workshops, but if you accept boxes from strangers and assemble them blindly, someone can slip in a trap.

How it works

A class implementing Serializable can be written with ObjectOutputStream.writeObject(obj) and read with ObjectInputStream.readObject(). All fields are saved except transient and static ones.

serialVersionUID identifies the class version. If it changes (or is missing and the class changes), reading old bytes throws InvalidClassException.

Hooks readObject, writeObject, readResolve customise the process (for example re-creating a singleton or validating state).

HTTP sessions in a cluster, caches (Redis with the JDK serializer), and JMS ObjectMessage often use it behind the scenes.

Going deeper

Never deserialize untrusted bytes. During readObject the JVM instantiates classes named in the stream and runs their methods; chains of common library classes (gadget chains) turn that into arbitrary code execution. Use an ObjectInputFilter allow-list at minimum, and prefer JSON or Protobuf for anything that crosses a trust boundary.

Serialized form leaks the internal structure of a class. Adding a field, renaming a class or moving a package breaks stored data, so long-lived data should use an explicit schema format instead.

Fields that are not serializable (connections, threads, loggers) must be transient or the write fails with NotSerializableException at runtime, often in production only.

Under the hood

The stream starts with class descriptors (name, UID, field names and types) followed by field values; object references are tracked in a handle table, so shared objects and cycles are preserved. Deserialization bypasses constructors for the serializable class, which is why invariants checked in constructors can be violated unless readObject validates them.

Common mistakes

  • Deserializing untrusted input.
  • Missing or changing serialVersionUID unintentionally.
  • Storing Java-serialized data long-term.
  • Non-transient fields holding resources.

How Unravel recognises it

When you paste code, Unravel looks for these signs of java serialization and its risks. Spotting them yourself is a good habit when you read unfamiliar code:

Part of a learning path

Related concepts

Frequently asked questions

What is Java serialization and its risks?

Java can turn an object graph into bytes (Serializable) and back. It is convenient and built into old frameworks (sessions, RMI, JMS object messages), but it is fragile across versions and a classic source of remote code execution.

What are the most common mistakes with Java serialization and its risks?

Deserializing untrusted input. Missing or changing serialVersionUID unintentionally. Storing Java-serialized data long-term. Non-transient fields holding resources.

How can I see Java serialization and its risks in real code?

Paste your own Java into Unravel and it will point out where java serialization and its risks appears, explain how it works at the detail level you choose, and draw the flow of the code around it.