Skip to content

Harden ObjectArrayMessage deserialization with SerializationUtil.assertFiltered#4098

Open
SunWeb3Sec wants to merge 4 commits intoapache:2.xfrom
SunWeb3Sec:harden-message-deserialization
Open

Harden ObjectArrayMessage deserialization with SerializationUtil.assertFiltered#4098
SunWeb3Sec wants to merge 4 commits intoapache:2.xfrom
SunWeb3Sec:harden-message-deserialization

Conversation

@SunWeb3Sec
Copy link
Copy Markdown

@SunWeb3Sec SunWeb3Sec commented Apr 19, 2026

Harden ObjectArrayMessage.readObject() with SerializationUtil.assertFiltered()

Summary

Adds a single SerializationUtil.assertFiltered(in) call at the top of ObjectArrayMessage.readObject(), bringing it in line with the defensive pattern already used by ObjectMessage and ParameterizedMessage.

Change

log4j-api/.../message/ObjectArrayMessage.java

Before

private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
    in.defaultReadObject();
    array = (Object[]) in.readObject();
}

After

private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
    SerializationUtil.assertFiltered(in);
    in.defaultReadObject();
    array = (Object[]) in.readObject();
}

Plus the corresponding import org.apache.logging.log4j.util.internal.SerializationUtil;.

What this PR deliberately does not do

  • Does not change the serialized wire format — ObjectArrayMessage instances produced by older versions still deserialize into a patched version, and vice versa.
  • Does not touch LocalizedMessage or FormattedMessage. They have similar gaps, but the Log4j security team scoped this request to ObjectArrayMessage only. Happy to submit follow-up PRs for those if desired.
  • Does not modify existing tests (LocalizedMessageTest#testSerialization*, FormattedMessageTest#testSerialization) that use plain ObjectInputStream, because those classes are untouched.

Tests

Added a minimal round-trip test (ObjectArrayMessageTest#testSerializableRoundTripThroughFilteredStream) that serializes and deserializes through SerialUtil, which uses FilteredObjectInputStream on Java 8 — verifying the new assertFiltered() call accepts filtered streams.

Behavioral note

On Java 8, deserializing an ObjectArrayMessage through a plain ObjectInputStream (no JEP 290 filter) now throws IllegalArgumentException instead of silently proceeding. This matches the existing behavior of ObjectMessage and ParameterizedMessage. Callers that relied on unfiltered deserialization of ObjectArrayMessage should wrap their streams in FilteredObjectInputStream, matching the project's guidance for the sibling message types.

On Java 9+, the behavior is unchanged — assertFiltered() is a no-op when a JVM-level ObjectInputFilter is active, and a warning otherwise.

Checklist

  • Single class changed (ObjectArrayMessage)
  • No wire format change
  • No new public API
  • No new dependencies
  • Unit test added
  • Changelog entry: src/changelog/.2.x.x/harden_message_deserialization.xml (type changed)

References

  • Private discussion with the Apache security team (closed as Informative — not a vulnerability; code-quality improvement welcomed).
  • Hardened siblings for reference:
    • ObjectMessage#readObject
    • ParameterizedMessage#readObject

Thanks to the Apache security team for the clear triage.

…rtFiltered

Adds a SerializationUtil.assertFiltered(in) call at the top of
ObjectArrayMessage#readObject, bringing it in line with the defensive
pattern already used by ObjectMessage and ParameterizedMessage.

This is a defense-in-depth / consistency fix; the serialized wire
format is unchanged so instances produced by older versions continue
to round-trip.

Signed-off-by: SunWeb3Sec <infosecpt@gmail.com>
@vy vy self-assigned this Apr 28, 2026
@vy vy added the enhancement Additions or updates to features label Apr 28, 2026
@vy vy added this to the 2.26.0 milestone Apr 28, 2026
@vy
Copy link
Copy Markdown
Member

vy commented Apr 28, 2026

@SunWeb3Sec, would you mind applying this DiD in all private void readObject\((final )?ObjectInputStream hits, please? You can skip tests, just do the necessary changes along with a very brief change log entry.

SunWeb3Sec and others added 2 commits April 29, 2026 07:52
…tream)

Extends the previous ObjectArrayMessage hardening to every remaining
private void readObject(ObjectInputStream) implementation across
log4j-api, log4j-core, log4j-1.2-api, log4j-slf4j-impl, log4j-slf4j2-impl,
and log4j-perf-test, per reviewer request.

Defense-in-depth only; serialized wire format is unchanged.

Signed-off-by: SunWeb3Sec <infosecpt@gmail.com>
@SunWeb3Sec
Copy link
Copy Markdown
Author

@vy Done, broadened to all private void readObject(ObjectInputStream) hits across the listed modules. Please review. thanks

Comment thread src/changelog/.2.x.x/harden_message_deserialization.xml Outdated
Copy link
Copy Markdown
Member

@vy vy left a comment

Choose a reason for hiding this comment

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

@SunWeb3Sec, thanks so much for the contribution and prompt reaction. Changes LGTM.

@vy vy enabled auto-merge (squash) April 29, 2026 09:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement Additions or updates to features

Projects

Development

Successfully merging this pull request may close these issues.

2 participants