Proof/CVE-2026-64606
Apache Fory's Java deserializer correctly rejected an ordinary unregistered lambda capture class. An interface with the same job slipped through — because "no default methods" was treated as proof the type was inert. It wasn't; it still ran attacker-controlled code.
Class registration is one of the controls that makes a general-purpose object serializer usable at a trust boundary. When a receiver enables strict registration, an unregistered application class should not become executable simply because its name appears in attacker-controlled bytes.
With strict registration enabled, an unregistered application type must not participate in executable deserialization.
The bug was not that Fory could deserialize Java lambdas. The bug was that one part of the policy classified an interface as a harmless class token while another part of the runtime used that same interface as executable lambda-restoration code.
The vulnerable rule admitted interfaces that had no Java default methods. For ordinary type tokens, that can look like a reasonable compatibility exception. For a SerializedLambda capture class, it was the wrong property to test.
strict mode:
allow registered classes
allow known safe tokens
allow interface when !hasDefaultMethods(interface)
lambda restore:
load capturing class
checkClassForDeserialization(capturingClass)
invoke SerializedLambda restorationA Java interface can contain executable static methods without containing a single default method. When a serializable lambda is defined there, the compiler can emit both a lambda body and a generated $deserializeLambda$ restoration method. The interface passes the “no default methods” test and still acts as executable restoration machinery.
Attacker controls lambda metadata and captured arguments.
No default methods becomes an admission signal.
Generated capture-class restoration code is invoked.
Comparator runs while the object graph is rebuilt.
A separate sender JVM serialized a comparator lambda and attacker-controlled captured data. The receiver did not share registration state with the writer.
The reader used requireClassRegistration(true) and registered zero application classes.
The equivalent unregistered capture class was rejected. This proved the registration boundary was active rather than accidentally disabled.
The interface had no default methods, so the generic safe-token exception approved it even though it contained generated lambda restoration code.
Fory rebuilt a PriorityQueue. Queue reconstruction invoked the restored comparator inside deserialize(), reaching the captured behavior before the call returned.
The finding was promoted only after the successful case, the negative control and the fixed control were retained together.
Unregistered capture class rejected with strict registration active.
Unregistered interface admitted; restored behavior invoked during deserialization.
Capture class blocked before lambda restoration when explicit policy is enforced.
A type filter that runs after code-bearing restoration is not a security boundary. Neither is a generic “safe token” exception when that token becomes a callback target in a specialized deserializer.
The durable engineering rule is to classify a type by what the current path will do with it—not only by its surface syntax. In this path, the capture interface was not inert metadata. It was executable restoration state.
The AI-assisted workflow did not stop at a source warning. Each stage had to produce evidence or a refutation before the candidate could move forward.
Trace capture-class metadata into the active registration policy and isolate the exception.
Challenge the assumption that “no default methods” means “no executable behavior.”
Build the smallest graph that restores the lambda and naturally invokes it during deserialization.
Separate JVMs, zero registrations, ordinary-class negative control, exact marker and fixed control.
Review the source, replay, impact, version range, wording and public-safety boundary before reporting.
Apache's advisory classifies CVE-2026-64606 as Important. CISA's ADP supplied the 9.8 Critical CVSS 3.1 vector displayed by NVD. NVD had not yet published its own assessment when this article was prepared.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
The network score models an application that accepts Fory bytes from a remote, unauthenticated source and deserializes them automatically. The vulnerability is in the library boundary; actual deployment exposure still depends on whether untrusted bytes reach that API.
| Package lineage | Affected range | Fixed |
|---|---|---|
org.apache.fury:fury-core | 0.5.0 to < 0.11.0 | Move to current Fory lineage |
org.apache.fory:fory-core | 0.11.0 to < 1.4.0 | 1.4.0 |
The fix is not “look for this one interface.” The durable rule is that executable lambda metadata must not inherit trust from a generic class-token exception.
The bug lived between abstractions. Java said the interface had no default methods. The generic policy treated the interface as a safe token. SerializedLambda treated it as executable restoration code. A collection invoked the restored lambda while rebuilding attacker-controlled state.
The CVE is the identifier. The negative control is what made the claim defensible.
Credit: Discovered and reported by Charles Vosburgh. Research was AI-assisted through source mapping, hypothesis generation, runtime construction and skeptical validation; final review and disclosure ownership remained human.