Files

2.0 KiB

serialization

Companion code for the ankurm.com post "Java Serialization in 2026: Why It's Dangerous and What Replaced It." Module serialization in java-core-examples.

All explanation lives in the post; this module holds the runnable evidence and the captured output. Nothing here uses a real library gadget chain: the "attacker" classes are local classes that print a line.

Versions

Component Version
JDK 25.0.4.1+1 (Temurin, LTS)
Jackson (tools.jackson.core:jackson-databind) 3.2.3
protobuf-java 4.36.2
JMH 1.37
JUnit Jupiter 5.11.0
Hardware 2 vCPU x86-64 VM (timings are indicative, not a leaderboard)

Quickstart

export JDK25_HOME=/path/to/jdk-25
./scripts/run-all.sh        # rebuilds and regenerates everything in output/

What is in here

File Shows Output
UidInStreamDemo the serialVersionUID is stored in the stream; patching it gives InvalidClassException 01
src/versions/ two versions of one class compiled separately by run-all.sh, without and with an explicit UID 02, 03
ReadObjectRunsCodeDemo readObject of the class named in the stream runs before the cast; an allow-list filter stops it 04
ResourceLimitsDemo forged array length, deep graph, maxarray / maxdepth / maxbytes 05
RecordsDemo records run the canonical constructor on deserialization; ordinary classes run none 06
FilterFactoryDemo JEP 415 filter factory with a per-request context, on top of -Djdk.serialFilter 07
Codecs, Order, order.proto, FormatSizeDemo the same object as Java serialization, Jackson 3 JSON and Protobuf wire format (hand-coded, no protoc) 08
SerializationBenchmark JMH round trip of the three encoders 09
SerializationTest 11 assertions behind the claims above 10

The JMH run is 2 forks, 5 warmup and 8 measurement iterations of 1 s; re-running moves the numbers but the Java-serialization-is-slowest ordering held in every run here.