New challenge: Log4j RCE - allowlist bypass via MarshalledObject
A researcher reported a critical, unpatched RCE for Log4j on August 24, 2026. Two days later the report was stripped and the account deleted. It turns out Apache had already documented the same code path in July, and stated that it is not a security issue under their threat model. No CVE has been assigned.
Although this is not a zero-day, the insecure pattern can exist in applications. Weβve built a challenge that simulate the same vulnerability, it shows how allowlists fail and how you should patch it.
The vulnerability
Log4j has a filter called FilteredObjectInputStream. Its job is to stop deserialization attacks. It works off an allowlist of trusted classes.
java.rmi.MarshalledObject is on that allowlist. But a MarshalledObject stores its payload as a raw byte array. The filter only checks the outer wrapper. It never looks inside the bytes.
When that payload gets unpacked later, it runs through a brand new stream with no filter attached and it executes whatever is inside it.
Every serialised log event carries its message inside a MarshalledObject. When something reads that event through the filter, the payload unpacks automatically with no filtering at that stage.
But this only matters if an application is actually receiving serialised log events over a network in the first place. Log4j stopped shipping that kind of receiver back in version 2.9.0. An application has to deliberately build and expose this listener for successful exploitation of this vulnerability.
Perhaps, this is why Apache calls it hardening rather than a vulnerability. Their position has always been that deserialising un-trusted data is unsafe on its own terms, filter or no filter.
The exploit
An attacker builds a message object. The attacker wraps the whole thing in a MarshalledObject, which is the step that hides it from the filter.
That wrapped object gets packaged as a normal-looking log event and sent to a receiver.
The receiver reads the event like it reads any other log event. It sees a MarshalledObject, checks it against the allowlist, and lets it through. Then it calls .get() to unpack the object inside. That unpacking step runs with no filter.
If anything goes wrong during that last step, Log4j quietly swallows the error and falls back to a generic message. It fails silently.
The challenge
We rebuilt this insecure pattern as a developer security challenge. You will first hack it, sending the crafted payload and watching the filter let it through. Then you will find where the logic breaks and fix it properly.
Itβs a good exercise in learning the drawbacks of maintaining an allowlist, and how easily one can be bypassed.
Try this challenge now: Chapar Log.java
