Allowlist-Based Deserialization
Allowlist-based deserialization restricts deserialization to explicitly approved types instead of accepting arbitrary classes from serialized input. This reduces the set of classes an attacker can cause the application to instantiate and is a useful defense against unsafe deserialization attacks.
Deserialization converts serialized data back into objects. In Java, some serialization mechanisms can encode type information, so a deserializer that trusts incoming type metadata may end up creating classes the application never intended to accept.
An allowlist changes that trust model: before a serialized type is instantiated, the application checks whether that type is explicitly permitted. Types outside the approved set are rejected. The list should be narrow and based on the application's actual data model, rather than allowing broad packages or interfaces.
Allowlisting is a defense-in-depth measure, not a substitute for validating the serialized data itself. Applications should also authenticate or integrity-protect untrusted serialized data when appropriate, minimize dangerous deserialization features, and avoid exposing deserialization of arbitrary object graphs to untrusted clients.
In Java, the exact implementation depends on the serialization technology. Native Java serialization provides mechanisms such as `ObjectInputFilter` for restricting classes during deserialization, while JSON libraries have their own polymorphic-type controls. The important security property is the same: untrusted type information must not freely determine which classes can be instantiated.
Key points
- Permit only explicitly required serialized types.
- Reject unexpected classes before they are instantiated.
- Keep the allowlist narrow; package-wide or wildcard rules can weaken the defense.
- Treat allowlisting as defense in depth alongside input validation and integrity protection.
- Use the filtering or type-restriction mechanism appropriate to the serialization library.
Interview questions
Is allowlisting alone enough to make deserialization safe?
No. It limits which classes can be instantiated, but permitted classes can still have unsafe behavior or receive malicious values. A secure design should combine type restrictions with appropriate validation, resource limits, authentication or integrity protection, and a serialization format suitable for the trust boundary. The safest approach may also be to avoid native object deserialization for untrusted data entirely.
What problem does allowlist-based deserialization solve?
It prevents a deserializer from accepting arbitrary object types supplied through serialized data. The application defines the classes it actually expects and rejects other types. This reduces the available attack surface when handling untrusted serialized input.
Why is an allowlist generally preferable to a denylist for deserialization security?
A denylist tries to identify classes that are dangerous, but it is difficult to predict every class or gadget chain that could become exploitable. An allowlist instead starts from no permitted application types and explicitly adds the types required by the use case. That makes the trust boundary narrower and leaves unknown classes rejected by default.
How would you implement type restrictions in a Java backend using native serialization?
For native Java serialization, I would use the platform's deserialization filtering facilities, such as `ObjectInputFilter`, to constrain which classes can be resolved. The filter should permit only the application's required types and reject everything else that should not cross the trust boundary. I would also consider limits on object graph depth, references, and array sizes where appropriate.
What design choices make an allowlist effective in a production service?
I would define the smallest set of DTOs or domain types that the endpoint genuinely needs and reject everything else. The rule should be centralized and consistently applied across every deserialization path, including nested objects and polymorphic types. I would monitor rejected-type events, test the filter against malicious inputs, and avoid broad package or wildcard permissions.