Co-Authored-By: Claude Sonnet 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01KqJyCidz3ZgRyHABv2GVJh
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.