Skip to content

fix: remediate insecure object deserialization in BlobUtils [ACT-2842] - #181

Open
ethan ozelius (ethan-ozelius-contentful) wants to merge 2 commits into
masterfrom
act-2842
Open

fix: remediate insecure object deserialization in BlobUtils [ACT-2842]#181
ethan ozelius (ethan-ozelius-contentful) wants to merge 2 commits into
masterfrom
act-2842

Conversation

@ethan-ozelius-contentful

@ethan-ozelius-contentful ethan ozelius (ethan-ozelius-contentful) commented Jun 30, 2026

Copy link
Copy Markdown

Summary

  • Root cause: BlobUtils.fromBlob used ObjectInputStream.readObject() without restricting which classes could be deserialized, enabling gadget-chain RCE if an attacker could influence blob
    data (Wiz finding WS-I013-JAVA-00051, HIGH)
  • Fix: Override resolveClass with an allowlist of permitted types (HashMap, LinkedHashMap, ArrayList, and standard primitives) — any unexpected class throws InvalidClassException before
    instantiation
  • Defense-in-depth: Added validateBlobInput to reject null, empty, oversized (>1MB), and malformed (non-0xACED header) blobs before ObjectInputStream is ever opened
  • Tests: Added BlobUtilsTest covering round-trip happy paths, malicious class rejection, and all four input validation guards

@ethan-ozelius-contentful ethan ozelius (ethan-ozelius-contentful) changed the title do not merge allow-list stream reading [ACT-2842] Jun 30, 2026
@ethan-ozelius-contentful ethan ozelius (ethan-ozelius-contentful) changed the title allow-list stream reading [ACT-2842] fix: remediate insecure object deserialization in BlobUtils [ACT-2842] Jun 30, 2026

@mariuskatcontentful mariuskatcontentful left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Looks good except for 1 bug that should be addressed :)

"[B" // byte[]
));

private static void validateBlobInput(byte[] blob) throws IOException {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ArrayIndexOutOfBoundsException on short blobs — this seems to only check length == 0, then unconditionally reads blob[0] and blob[1]. A 1-byte blob crashes with an unchecked exception instead of a controlled validation error. Fix: check blob.length < 2 before header check.

Try feeding a 1-byte blob ({0xAC}). Result:

ArrayIndexOutOfBoundsException: Index 1 out of bounds for length 1

No test coverage for this edge case either — BlobUtilsTest.java tests a 4-byte malformed header but never a 1-byte blob, so bug was undetected.

Additional code would prevent it here:

.... if (blob.length > MAX_BLOB_SIZE) { throw new IllegalArgumentException("Blob exceeds maximum allowed size"); } if (blob.length < 2) { throw new InvalidClassException("Invalid serialized format: blob too short to contain a header"); } if ((blob[0] & 0xFF) != (SERIAL_MAGIC_1 & 0xFF) || (blob[1] & 0xFF) != (SERIAL_MAGIC_2 & 0xFF)) { throw new InvalidClassException("Invalid serialized format: missing Java serialization header"); } ....

Also adding additional mentioned test:

@Test(expected = InvalidClassException.class) public void testTooShortBlobRejected() throws Exception { BlobUtils.fromBlob(HashMap.class, new byte[]{(byte) 0xAC}); }

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.

2 participants