A critical, newly disclosed remote code execution (RCE) vulnerability has been identified in Apache Log4j2, specifically targeting its deserialization mechanisms. Tracked internally as Issue #4255 and reported by U-Sec (Wujie Security), this flaw allows attackers to bypass the FilteredObjectInputStream (FOIS) allowlist via java.rmi.MarshalledObject. The vulnerability affects log4j-api versions 2.11.0 through 2.26.1 and log4j-core versions 2.8.0 through 2.26.1.
Unlike the infamous Log4Shell (CVE-2021-44228), which exploited JNDI lookups via malformed log strings, this vulnerability requires a specific architectural setup: an application must be actively receiving serialized Java LogEvent objects over a network socket using Log4j’s built-in deserialization bridges. When successfully exploited, the vulnerability enables silent, unfiltered Java deserialization, leading to arbitrary code execution, resource-exhaustion denial-of-service (DoS) via object-graph bombs, or malicious log injection.
This comprehensive technical analysis breaks down the root cause, the exact exploitation mechanics, affected environments, and actionable, enterprise-grade mitigation strategies aligned with current cybersecurity best practices.
What is the Log4j2 FilteredObjectInputStream Bypass Vulnerability?
Apache Log4j2 introduced FilteredObjectInputStream (FOIS) as a defense-in-depth mechanism to mitigate the inherent dangers of Java native deserialization (CWE-502). Java deserialization is notoriously risky because reconstructing an object from a byte stream can inadvertently execute malicious code if the stream contains a crafted “gadget chain” (a sequence of classes that, when deserialized, perform unintended actions).
To counter this, FOIS implements a strict allowlist via the resolveClass() method. When a serialized object is read, FOIS checks its class name against a hardcoded set of REQUIRED_JAVA_CLASSES. If the class is not on the list, deserialization is immediately halted with an InvalidObjectException.
However, Issue #4255 reveals a fundamental architectural flaw in how this allowlist interacts with java.rmi.MarshalledObject. A MarshalledObject is a Java RMI class designed to encapsulate a serialized object as an opaque byte array (objBytes), deferring its actual deserialization until the get() method is explicitly called. Because the outer MarshalledObject itself is on the FOIS allowlist, the initial resolveClass() check passes. The critical failure occurs when Log4j’s own internal logic automatically invokes MarshalledObject.get(), which instantiates a brand new, plain ObjectInputStream to unpack the inner byte array. This inner stream completely bypasses the FOIS allowlist, rendering the defense-in-depth mechanism useless and exposing the application to the full spectrum of Java deserialization exploits.
Technical Deep Dive: How the Exploit Works
To fully grasp the severity of this vulnerability, we must examine the exact code paths and Java serialization lifecycle events that make this exploit possible. The vulnerability is not a result of operator misconfiguration, but rather an auto-triggering flaw within Log4j’s own serialization format.

1. The Allowlist Blind Spot
The root cause begins in log4j-api’s SerializationUtil.java. The FOIS allowlist explicitly permits java.rmi.MarshalledObject:
// log4j-api/src/main/java/org/apache/logging/log4j/util/internal/SerializationUtil.javaprivate static final Set<String> REQUIRED_JAVA_CLASSES = new HashSet<>(Arrays.asList( "java.rmi.MarshalledObject", "[B" // byte array // ... other allowed classes));
When FilteredObjectInputStream.resolveClass() is called during deserialization, it only inspects the top-level class descriptor. It sees java.rmi.MarshalledObject, verifies it against the allowlist, and permits it. The opaque objBytes payload hidden inside the MarshalledObject remains completely invisible to this filter.
2. The Auto-Trigger Mechanism in Log4j-Core
The vulnerability transitions from a theoretical bypass to a practical exploit due to how Log4j handles serialized log events. Since version 2.8, Log4j uses a proxy pattern for serializing LogEvent objects. The Log4jLogEvent.LogEventProxy class contains a field specifically designed to hold the marshalled message:
// log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.javaprivate transient MarshalledObject<Message> marshalledMessage;
When the receiving application deserializes the LogEventProxy, Java’s serialization mechanism automatically invokes the readResolve() method. This method is designed to replace the deserialized proxy with the actual LogEvent object. During this process, it calls the message() method to reconstruct the log message:
// log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.javaprivate Message message() { if (marshalledMessage != null) { try { // CRITICAL FLAW: This creates a NEW, plain ObjectInputStream // with NO custom resolveClass() filtering applied. return marshalledMessage.get(); } catch (final Exception ex) { // CRITICAL FLAW: Exceptions are silently swallowed. /* ignore me */ } } return new SimpleMessage(messageString);}
3. The Silent Execution and Exception Swallowing
The combination of the unfiltered inner stream and the silent exception handling creates a highly stealthy attack vector. When marshalledMessage.get() is called, it deserializes the attacker’s malicious gadget chain (e.g., Commons Collections, Jdk7u21). The gadget executes its payload (such as spawning a reverse shell or executing arbitrary OS commands).
After the gadget executes, the deserialization process inevitably results in a ClassCastException because the deserialized object is not a valid Log4j Message interface implementation. However, because the catch block explicitly ignores all exceptions, the Log4j receiver does not crash or log an error. Instead, it gracefully falls back to creating a SimpleMessage using a benign string, making the receiver appear to have processed a normal, harmless log event. This silence significantly complicates incident response and detection efforts.
Affected Versions and Environment Scope
Understanding the precise scope of this vulnerability is critical for accurate risk assessment and patch prioritization. The vulnerability is platform-independent and affects all tested JDK versions, though the mechanics differ slightly between Java 8 and JDK 9+.
| Component | Affected Versions | Notes |
|---|---|---|
log4j-api | 2.11.0 – 2.26.1 | Contains the flawed FilteredObjectInputStream and SerializationUtil. |
log4j-core | 2.8.0 – 2.26.1 | Contains the Log4jLogEvent.LogEventProxy auto-trigger mechanism. |
| JDK 8 | All Updates | Highly vulnerable. Java 8 lacks the modern ObjectInputFilter API entirely, relying solely on the flawed resolveClass() override. |
| JDK 9+ | All Updates | Vulnerable. While JDK 9+ allows MarshalledObject to copy the stream’s ObjectInputFilter, Log4j’s FOIS never calls setObjectInputFilter(). Therefore, the captured filter is null, making the protection a no-op. |
Crucial Scope Limitation: This is an application-conditional vulnerability, not a universal Log4j RCE like Log4Shell. For an exploit to succeed, the target environment must meet two specific criteria:
- The application must be actively running a service that receives serialized
LogEventobjects over a network (e.g., usingObjectInputStreamLogEventBridgeor legacyTcpSocketServer). - The target application’s classpath must contain a usable deserialization gadget library (such as an unpatched version of Apache Commons Collections, typically version 3.2.1 or older).
If an organization uses Log4j strictly for local file logging or standard JSON/TCP syslog forwarding without Java native serialization, they are not directly vulnerable to this specific attack vector.
Attack Vectors and Real-World Impact
The practical exploitation of this vulnerability requires an attacker to send a single, crafted TCP payload to a vulnerable receiver. The researcher’s proof-of-concept demonstrates a “fire-and-forget” attack requiring only a single ~2.8 KB network write.
Primary Attack Scenarios
- Legacy Socket Servers: Deployments using Log4j versions ≤ 2.8.2 may still utilize the deprecated
org.apache.logging.log4j.core.net.server.TcpSocketServer.createSerializedSocketServer. If exposed to untrusted networks, this is a direct RCE vector. - Custom or Sample Bridges: Applications that have copied Apache’s official
ObjectInputStreamLogEventBridgesample code, or third-party analytics servers (likevertigo-analytics-server) that default to FOIS-based serialized socket servers without TLS or authentication. - Object-Graph Bomb DoS: Even if a viable RCE gadget chain is not present on the target’s classpath, an attacker can craft a deeply nested, highly repetitive serialized object graph (a “zip bomb” equivalent for deserialization). When the unfiltered inner stream attempts to process this, it can consume massive amounts of CPU and memory, leading to a resource-exhaustion Denial of Service.
- Log Injection: Attackers can inject arbitrary, attacker-chosen log content into downstream appenders, potentially poisoning SIEM systems, triggering false-positive alerts, or facilitating secondary social engineering attacks against system administrators.
The Gadget Chain Dependency
The exploit’s success hinges on the presence of a vulnerable gadget chain. For example, if the target server has commons-collections:3.2.1 on its classpath, the attacker can splice a CommonsCollections6 payload into the MarshalledObject‘s objBytes. Because the inner deserialization is unfiltered, the gadget chain executes flawlessly. Notably, if the target has upgraded to commons-collections:3.2.2 (which disables unsafe functor deserialization), this specific gadget chain will fail silently, though alternative gadget chains (e.g., JDK native gadgets) might still be viable depending on the exact JDK version.
Step-by-Step Mitigation and Remediation Strategies
Given the public disclosure of Issue #4255, organizations must act swiftly to assess their exposure and implement mitigations. Because an official patched release from the Apache Log4j team is still pending (the issue remains labeled waiting-for-maintainer), defense-in-depth and configuration-based workarounds are currently the primary lines of defense.
Immediate Mitigation: JVM-Level Serial Filtering
For environments running JDK 9 or higher, the most reliable immediate workaround is to enforce a global JVM serialization filter that explicitly rejects java.rmi.MarshalledObject. This can be achieved by adding the following argument to the JVM startup command of the receiving application:
# Add this to your JVM startup arguments (e.g., in catalina.sh, systemd service, or Docker ENTRYPOINT)-Djdk.serialFilter='!java.rmi.MarshalledObject;*;'
Important Caveat: This mitigation is a blunt instrument. Because legitimate Log4j LogEventProxy objects also rely on MarshalledObject for transport, applying this filter will break legitimate serialized log forwarding between trusted internal services. It should only be applied if your architecture does not rely on native Java serialized log transport, or as an emergency stopgap while a more permanent solution is engineered.
Structural Mitigation: Architectural Changes
The most robust, long-term solution is to eliminate the attack surface entirely by abandoning Java native serialization for log transport. Native serialization is widely considered an anti-pattern in modern, secure network architecture.
- Migrate to Safe Formats: Transition all log forwarding mechanisms to use safe, structured data formats such as JSON, RFC 5424 (Syslog), or Protocol Buffers over authenticated, encrypted channels (TLS 1.2+).
- Network Segmentation: If legacy serialized receivers must remain active, enforce strict network-level controls. Use firewall rules to ensure that the ports hosting these receivers (e.g., default port 4563 in sample configurations) are only accessible from explicitly trusted, internal IP addresses. Never expose these ports to the public internet or DMZ segments.
- Dependency Hygiene: Conduct a thorough audit of your application’s classpath using Software Composition Analysis (SCA) tools. Remove or upgrade known dangerous libraries, such as Apache Commons Collections < 3.2.2, old versions of Spring Framework, or other libraries known to harbor deserialization gadgets.
Anticipated Vendor Fix (For Tracking)
The vulnerability reporter has proposed two viable paths for the Apache Log4j maintainers to resolve this issue permanently:
- Option A (Minimal Fix): Remove
java.rmi.MarshalledObjectfrom theREQUIRED_JAVA_CLASSESallowlist inSerializationUtil.java. Simultaneously, modify the transport mechanism to useSerializationUtil.writeWrappedObject()andreadWrappedObject(), which utilize a plain byte array paired with an inner FOIS, ensuring the filter is applied to the payload. This approach maintains compatibility with Java 8. - Option B (Structural Fix): Migrate the FOIS implementation to utilize the modern JEP 290
ObjectInputFilterAPI. This API is capable of inspecting the stream more deeply and can see through theMarshalledObjectwrapper on JDK 9+, providing a more robust, native-level defense.
Organizations should monitor the Apache Log4j Security Advisories page for the official CVE assignment and patch release corresponding to Issue #4255.
Detection and Monitoring: How to Identify Exploitation Attempts
Because the vulnerability is designed to fail silently (swallowing the ClassCastException), traditional application error logs will not reliably indicate an attack. Security teams must rely on network and host-level telemetry to detect exploitation attempts.
Network Intrusion Detection System (NIDS) Signatures
Monitor network traffic for anomalous, unauthenticated connections to known log-receiving ports (e.g., TCP 4563, 5000, or custom application ports). Look for the following patterns:
- Small, abrupt TCP connections (often just a few kilobytes) that immediately terminate after sending a payload (the “fire-and-forget” sketch).
- Payloads beginning with the Java serialization magic number:
AC ED 00 05(hex), followed shortly by references tojava.rmi.MarshalledObjectandorg.apache.logging.log4j.core.impl.Log4jLogEvent$LogEventProxy.
Endpoint Detection and Response (EDR) Alerts
Configure EDR solutions to alert on suspicious process execution patterns that are hallmarks of deserialization gadget chains:
- A Java process (
java.exeorjava) spawning unexpected child processes, particularly shell interpreters (/bin/sh,cmd.exe,powershell.exe) or network utilities (curl,wget,nc,bash -i). - Sudden, unexplained spikes in CPU or memory utilization by a Java process, which may indicate an object-graph bomb DoS attempt rather than a successful RCE.
Log Analysis Queries (SIEM)
While the receiver may not log an error, you can search for the successful fallback behavior. A query looking for an unusually high volume of SimpleMessage logs originating from network-based appenders, especially from unexpected source IPs, may indicate that malformed payloads are being processed and silently downgraded.
Frequently Asked Questions (FAQ)
Is this vulnerability the same as Log4Shell (CVE-2021-44228)?
No. Log4Shell was a JNDI injection vulnerability triggered by logging a specific malicious string (e.g., ${jndi:ldap://...}). This new vulnerability (Issue #4255) is a Java deserialization flaw that requires the application to actively receive and deserialize raw Java byte streams over a network. The attack vectors and mitigation strategies are entirely different.
Am I vulnerable if I only use Log4j to write logs to a local file?
No. This vulnerability specifically targets the FilteredObjectInputStream used when receiving serialized log events over a network. If your application only uses Log4j to write logs to local files, consoles, or standard JSON/TCP syslog outputs (without Java native serialization), you are not affected by this specific flaw.
Does upgrading to Log4j 2.26.1 fix this issue?
No. The vulnerability has been verified against the official 2.26.1 artifacts from Maven Central. The issue remains unpatched in all versions up to and including 2.26.1. You must rely on the JVM-level workarounds or architectural changes detailed in the mitigation section until Apache releases an official patch.
Will the -Djdk.serialFilter='!java.rmi.MarshalledObject' workaround break my application?
It might. If your application legitimately relies on Log4j’s native serialized socket receivers to forward logs between trusted internal services, this filter will block those legitimate LogEventProxy objects, causing log forwarding to fail. It is highly recommended to test this flag in a staging environment that mirrors your production architecture before deploying it globally.
How can I check if my application has a vulnerable gadget chain on its classpath?
You can use Software Composition Analysis (SCA) tools such as OWASP Dependency-Check, Snyk, or GitHub Dependabot to scan your project’s pom.xml or build.gradle files. Specifically, look for outdated versions of libraries notorious for deserialization gadgets, such as commons-collections (versions prior to 3.2.2), commons-beanutils, or older versions of groovy.
Conclusion
The Log4j2 FilteredObjectInputStream Bypass Vulnerability (Issue #4255) serves as a stark reminder of the inherent complexities and dangers of Java native deserialization. While Log4j’s implementation of FilteredObjectInputStream was designed as a robust defense-in-depth measure, the automatic, unfiltered unwrapping of java.rmi.MarshalledObject by LogEventProxy creates a critical blind spot.
For security professionals and system administrators, the immediate priority is to identify any services utilizing Log4j’s serialized network receivers. If such services exist and face untrusted networks, they must be immediately isolated or protected via JVM serial filtering. Long-term, the industry must continue its migration away from native Java serialization toward secure, structured data formats like JSON over TLS.
As the open-source community awaits an official patch from the Apache Log4j maintainers, vigilance, strict network segmentation, and proactive dependency management remain the most effective shields against this emerging threat. We will continue to monitor the Apache issue tracker and update this analysis as soon as an official CVE is assigned and a patch is released.
Disclaimer: This article is for educational and defensive cybersecurity purposes. The technical details provided are intended to help organizations understand, detect, and mitigate the vulnerability. Do not test or deploy exploitation techniques against systems you do not own or have explicit written authorization to assess.
This post first appeared at - The CyberSec Guru