Skip to content

Implement ObjectInputFilter allowlist for legacy object deserialization - #838

Open
AliRana30 wants to merge 1 commit into
apache:mainfrom
AliRana30:fix/object-input-filter-835
Open

AliRana30 wants to merge 1 commit into
apache:mainfrom
AliRana30:fix/object-input-filter-835

Conversation

@AliRana30

Copy link
Copy Markdown
Contributor

What changes?

  1. ObjectFileSerialization:
    • Adds createObjectInputFilter(Class<?> elementType) to restrict legacy object deserialization to expected primitives, wrappers, standard safe collections, Wayang types, Scala tuples, and expected elementType hierarchies.
    • Adds dynamic allowlist pattern configuration via wayang.basic.serialization.allowlist.
    • Rejects unauthorized classes with InvalidClassException.
  2. WayangValue:
    • Enforces the ObjectInputFilter on Flink criterion deserialization.
    • Refactors convertToByte and convertToObject to use try-with-resources.
  3. Tests:
    • Added unit test cases to verify rejection of disallowed classes, explicit elementType acceptance, and system property pattern matching.

Why are the changes needed?

Directly calling ObjectInputStream.readObject() without an ObjectInputFilter allows arbitrary class instantiation, posing a deserialization security risk (CWE-502).

How was this tested?

  • Unit tests added to ObjectFileSerializationTest and WayangValueTest.
  • Ran mvn test on wayang-basic and wayang-flink.
  • Ran mvn apache-rat:check.

Closes : #835

Copilot AI balanced review requested due to automatic review settings October 10, 2026 23:02

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@AliRana30

Copy link
Copy Markdown
Contributor Author

@zkaoudi Pr is up for your review.

@novatechflow

Copy link
Copy Markdown
Member

Thanks for the fix. Three issues to address before merging:

  • The allowlist accepts arbitrary Number, Collection, and Map subclasses. Custom readObject() hooks still execute.
  • A fresh WayangValue rejects valid custom payloads and silently returns null because the expected type comes from previous data.
  • List.of(), Set.of(), and Map.of() fail deserialization because java.util.CollSer is missing.

Reproduced all three on Java 17. Please tighten the allowlist and add regression tests.

@AliRana30
AliRana30 force-pushed the fix/object-input-filter-835 branch from 05351a2 to c2850f7 Compare October 21, 2026 23:02
@AliRana30

Copy link
Copy Markdown
Contributor Author

@novatechflow Updated the allowlist and WayangValue as per the feedback. Alos added regression tests for all three cases in ObjectFileSerializationTest and WayangValueTest. Verified clean build on Java 17

@novatechflow

Copy link
Copy Markdown
Member
  • Allowlist bypass: Number.class still permits arbitrary subclasses, and specifying a payload type trusts unrelated classes in its package. Custom readObject() hooks execute in both cases.
  • Fresh Flink values: a no-argument WayangValue still rejects valid custom payloads with InvalidClassException.
  • New tests manually supply the type; Flink’s fresh-value path is still uncovered.

Immutable collections now round-trip correctly, and deserialization failures propagate instead of silently returning null. Great work!

@AliRana30
AliRana30 force-pushed the fix/object-input-filter-835 branch from c2850f7 to 91bacd7 Compare October 24, 2026 21:36
@AliRana30

Copy link
Copy Markdown
Contributor Author

@novatechflow Updated the PR and added the following :
1.Restricted Number to boxed primitives/math types and collections/maps to java.util.* implementations to prevent arbitrary subclasses from executing custom readObject() hooks.
2.Added explicit type support (type field, constructors, getters/setters, and convertToObject overload) to WayangValue for fresh instances and replaced silent null returns with WayangException.
3.Allowed java.util.CollSer to support Java 9+ List.of(), Set.of(), and Map.of().
4.Added regression tests covering all three cases in ObjectFileSerializationTest and WayangValueTest. Verified on Java 17.

@novatechflow

Copy link
Copy Markdown
Member

Took a bit longer to check and write a proper review since its sec relevant, three blockers still reproduced with Java 17:

  • Number.class permits custom subclasses whose readObject() hooks execute.
  • A payload type permits unrelated classes in its package; their hooks execute.
  • A fresh no-argument WayangValue rejects valid custom payloads.
  1. Arbitrary subclasses remain allowed.
    ObjectFileSerialization.java:228–229 accepts any class assignable to the expected type. With Number.class, this includes custom Number subclasses, bypassing the earlier boxed-number restriction.

    Implication: custom readObject() hooks execute. The intended security boundary remains bypassable; actual harm depends on available classes and input control.

  2. An expected type trusts its entire package and subpackages.
    ObjectFileSerialization.java:234–236 permits unrelated classes whose names start with the expected type’s package.

    Implication: selecting one legitimate payload class also permits unrelated classes and their deserialization hooks. The probe confirmed hook execution.

  3. Fresh Flink values still lack the expected type.
    The no-argument constructor sets both data and type to null. Deserialization consequently installs a filter without an expected custom type.

    Implication: valid custom payloads fail with InvalidClassException when read into fresh instances. The regression test manually supplies CustomPayload.class, so it does not cover this failing path.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Improvement] Implement ObjectInputFilter allowlist for legacy object deserialization

3 participants