GHSA-LOG4J2-4255-MARSHALLEDOBJECT: Verified Reproduction
GHSA-LOG4J2-4255-MARSHALLEDOBJECT: Apache Log4j2 serialized LogEvent filter bypass to conditional RCE
GHSA-LOG4J2-4255-MARSHALLEDOBJECT is verified against org.apache.logging.log4j:log4j-core · maven. Affected versions: log4j-api 2.11.0-2.26.1; log4j-core 2.8.0-2.26.1 (verified against official 2.26.1 jars from Maven Central). Fixed in none yet - upstream issue open, waiting-for-maintainer label; no CVE/GHSA assigned. Vulnerability class: RCE. This critical reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00338.
What Is GHSA-LOG4J2-4255-MARSHALLEDOBJECT?
GHSA-LOG4J2-4255-MARSHALLEDOBJECT is a critical-severity RCE vulnerability affecting org.apache.logging.log4j:log4j-core log4j-api 2.11.0-2.26.1; log4j-core 2.8.0-2.26.1 (verified against official 2.26.1 jars from Maven Central). Pruva has independently reproduced it and publishes a verified, runnable proof-of-concept (reproduction REPRO-2026-00338).
GHSA-LOG4J2-4255-MARSHALLEDOBJECT Severity
GHSA-LOG4J2-4255-MARSHALLEDOBJECT is rated critical severity.
Critical — the most severe class — typically remotely exploitable with severe impact. Treat as an emergency.
Affected org.apache.logging.log4j:log4j-core Versions
org.apache.logging.log4j:log4j-core · maven versions log4j-api 2.11.0-2.26.1; log4j-core 2.8.0-2.26.1 (verified against official 2.26.1 jars from Maven Central) are affected.
How to Reproduce GHSA-LOG4J2-4255-MARSHALLEDOBJECT
pruva-verify REPRO-2026-00338 curl -O https://www.pruva.dev/api/v1/reproductions/REPRO-2026-00338/artifacts/bundle/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh Proof of Reproduction for GHSA-LOG4J2-4255-MARSHALLEDOBJECT
- reached the target end-to-end
- full exploit chain demonstrated
- on the real production code path
- high confidence
- the upstream fix blocks the same trigger
One exact serialized Log4jLogEvent.LogEventProxy byte stream whose MarshalledObject contains a Commons Collections CC6 Runtime.exec graph, replayed over unauthenticated TCP to vulnerable and patched receivers (payload SHA-256 recorded in logs/payload_identity.txt).
- Apache logging-log4j-samples TcpSocketServer.SocketHandler accepts TCP
- ObjectInputStreamLogEventBridge.wrapStream
- FilteredObjectInputStream(socket.getInputStream()).readObject
- Log4jLogEvent.LogEventProxy.readResolve/message
- MarshalledObject.get
- inner ObjectInputStream
- CC6 Runtime.exec.
reproduction_steps.sh How the agent worked
Root Cause and Exploit Chain for GHSA-LOG4J2-4255-MARSHALLEDOBJECT
- Validated product path:
org.apache.logging.log4j.server.TcpSocketServerwithObjectInputStreamLogEventBridgefrom Apachelogging-log4j-samplescommit672a1555c7f5670e7affcc7b9984a90b492eb322, running official Log4j API/Core 2.26.1 artifacts. - Risk: Critical where this unauthenticated serialized-event listener is reachable and a usable gadget library is on the receiver classpath. An attacker can bypass the intended class allowlist and execute commands with the receiver process account.
Impact Parity
- Disclosed/claimed maximum impact: Remote unauthenticated arbitrary deserialization leading to code execution.
- Reproduced impact from this run: Remote receiver-side command execution through the required TCP entrypoint. A single generated CC6 payload file was replayed unchanged to two vulnerable JVM instances and produced process-unique
PWNED-TIER2markers containing receiver-side shell and parent process IDs plus account identity. - Parity:
full. - Not demonstrated: Privilege escalation beyond the account running the receiver was not claimed or tested.
Root Cause
Vulnerable log4j-api includes java.rmi.MarshalledObject in SerializationUtil.REQUIRED_JAVA_CLASSES. FOIS checks outer class descriptors in resolveClass(), but the object graph stored by MarshalledObject is opaque bytes at that stage. During deserialization of Log4jLogEvent.LogEventProxy, readResolve() calls message(), which calls marshalledMessage.get(). That operation deserializes the inner graph in another ObjectInputStream, outside FOIS's class-name check. A non-allowlisted object can therefore execute its readObject() callback, and a receiver-loadable gadget graph can reach Runtime.exec.
The tested minimal correction removes java.rmi.MarshalledObject from REQUIRED_JAVA_CLASSES, causing FOIS to reject the carrier before its inner bytes are unpacked. bundle/logs/fix.patch records the exact change. The upstream report is https://github.com/apache/logging-log4j2/issues/4255; it was still open at reproduction time and did not identify a merged fix commit, so the negative control applies the report's minimal suggested fix to official 2.26.1 source.
Reproduction Steps
- Run
bash bundle/repro/reproduction_steps.shfrom any directory. The script usesPRUVA_ROOTor resolves the bundle path itself. - It reads
bundle/project_cache_context.json, uses<project_cache_dir>/repowhen prepared, verifies the Apache samples origin and exact commit, and extracts the reallog4j-serversources. - It verifies official Log4j 2.26.1 and Commons Collections 3.2.1 jar hashes, compiles the real
TcpSocketServerandObjectInputStreamLogEventBridgeclasses, and records their runtimeCodeSourcepaths. - It generates each serialized payload once and sends the exact file bytes over localhost TCP. It performs direct unwrapped-object rejection, wrapped inner deserialization twice, wrapped CC6 command execution twice, the same tier-2 bytes against two patched receivers, and the same bytes against
-Djdk.serialFilter=!java.rmi.MarshalledObject. - It validates all assertions and writes
bundle/repro/runtime_manifest.json. Exit 0 means the claim is confirmed.
Evidence
- Exact identity:
bundle/logs/target_identity.txtbinds samples commit672a1555c7f5670e7affcc7b9984a90b492eb322, Log4j commitdd0f9d255e24e6bcc13bd2641407a409c0524803, official API/Core jar hashes, target digest7310f18dd2601851bcc37b1963906cbd86f417a18b196251c8fe64a6b3b18673, and runtime digest98b16715ef49ca21a5b32b7184a718cb9110ddc5269b06be0c3e3167467df639. - Exact attacker input:
bundle/logs/payload_identity.txtrecords the SHA-256 of each pre-generated input. The final tier-2 input has SHA-2564e3a504e6d390c37a57253a323d3d91382f8ef92caa95a9e2c2193f38a707217; sender logs prove identical byte count/file reuse across vulnerable, patched, and mitigated attempts. - Real TCP/product boundary:
bundle/logs/receiver_tier2_a1.logandreceiver_tier2_a2.logidentify loadedTcpSocketServer,ObjectInputStreamLogEventBridge, vulnerable API/Core jars, and Commons Collections; they then show binding, connection acceptance, socket details, and the deserialized event. - Command execution:
bundle/logs/tier2_rce_marker_a1.txtcontains tokenRCE-1787737383615632389-15376,shell_pid=39677, andparent_pid=39626; attempt a2 contains the same payload token but distinctshell_pid=39759andparent_pid=39708. Both includeuid=1000(vscode), proving execution in two fresh receiver contexts. - Direct control:
bundle/logs/receiver_control.logshowsObjectInputStreamLogEventBridge.logEvents()rejecting unwrappedpoc.GadgetOnlythroughFilteredObjectInputStream.resolveClass(). - Fixed controls:
bundle/logs/receiver_fixed_a1.logandreceiver_fixed_a2.logshow TCP acceptance followed byInvalidObjectException: Class is not allowed for deserialization: java.rmi.MarshalledObject; the shared command target is absent. - Mitigation:
bundle/logs/receiver_mitigation.logshows the same TCP/readObject path failing withInvalidClassException: filter status: REJECTEDand no marker. - Digest closure:
bundle/repro/runtime_manifest.jsonbinds 29 finalized proof artifacts to SHA-256 digests and recordsentrypoint_kind=tcp_peer, service/health/path success, and full target/runtime identity.
Recommendations / Next Steps
Remove java.rmi.MarshalledObject from the default Log4j deserialization allowlist and avoid unfiltered MarshalledObject.get() for event messages; use a filtered wrapped-object format instead. Upgrade to the first vendor release containing the final upstream correction once published. Do not expose Java serialized-event listeners to untrusted networks. As defense in depth, configure a JEP 290 class filter rejecting java.rmi.MarshalledObject, remove unnecessary gadget libraries, and add regression tests that replay a malicious event through the real TCP receiver and require fail-closed rejection.
Additional Notes
The final script was executed successfully twice consecutively after all amendments. Every execution uses isolated receiver JVMs and randomized ports, removes prior proof artifacts, generates a fresh payload token, and verifies exact payload-byte reuse across vulnerable and controls. Service startup, TCP health, and target-path reachability are tracked independently, and a failed run preserves digest-bound evidence from completed phases. The launcher does not implement a socket, parser, or readObject() path; it only selects serialized mode through TcpSocketServer.createSerializedSocketServer().
GHSA-LOG4J2-4255-MARSHALLEDOBJECT Reproduction Transcript
The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.
Full session Replay every step — scrub the timeline or play it back.
ls /pruva/project-cache 2>/dev/null; ls /pruva/project-cache/repo-mirrors 2>/dev/null; which java javac mvn; java -version 2>&1; python3 --version; curl -sI --max-time 8 https://repo1.maven.org/maven2/ | head -3repo-mirrors pruva-command: 1: java: not found Python 3.14.4 HTTP/2 200 date: Wed, 26 Aug 2026 08:37:03 GMT content-type: text/html
ls -la /pruva/project-cache/repo-mirrors; cat /pruva/project-cache/.pruva/cache_manifest.json 2>/dev/null; apt-cache policy openjdk-17-jdk-headless 2>/dev/null | head -5; whoami; sudo -n true && echo sudo-oktotal 0
drwx------ 2 vscode vscode 40 Aug 26 08:35 .
drwx------ 4 vscode vscode 80 Aug 26 08:35 ..
{
"schema_version": 1,
"entries": [
{
"path": "repo-mirrors",sudo apt-get update -qq 2>&1 | tail -2 && apt-cache search openjdk | grep -i jdk | head -10openjdk-25-dbg - Java runtime based on OpenJDK (debugging symbols) openjdk-25-jdk - OpenJDK Development Kit (JDK) openjdk-25-jdk-headless - OpenJDK Development Kit (JDK) (headless) openjdk-25-jre - OpenJDK Java runtime, using Hotspot JIT openjdk-25-jre-headless - OpenJDK Java runtime, using Hotspot JIT (headless) openjdk-25-source - OpenJDK Development Kit (JDK) source files jtreg - Regression Test Harness for the OpenJDK platform jtreg6 - Regression Test Harness for the OpenJDK platform
sudo apt-get install -y -qq openjdk-25-jdk-headless unzip >/tmp/jdk_install.log 2>&1; tail -2 /tmp/jdk_install.log; which java javac; java -version 2>&1update-alternatives: using /usr/lib/jvm/java-25-openjdk-amd64/bin/serialver to provide /usr/bin/serialver (serialver) in auto mode update-alternatives: using /usr/lib/jvm/java-25-openjdk-amd64/bin/jhsdb to provide /usr/bin/jhsdb (jhsdb) in auto mode /usr/bin/java /usr/bin/javac openjdk version "25.0.4" 2026-07-21 OpenJDK Runtime Environment (build 25.0.4+7-1-26.04-Ubuntu) OpenJDK 64-Bit Server VM (build 25.0.4+7-1-26.04-Ubuntu, mixed mode, sharing)
Artifacts and Evidence for GHSA-LOG4J2-4255-MARSHALLEDOBJECT
Scripts, logs, diffs, and output captured during the reproduction.
How to Fix GHSA-LOG4J2-4255-MARSHALLEDOBJECT
Upgrade org.apache.logging.log4j:log4j-core · maven to none yet - upstream issue open, waiting-for-maintainer label; no CVE/GHSA assigned or later.
FAQ: GHSA-LOG4J2-4255-MARSHALLEDOBJECT
Is GHSA-LOG4J2-4255-MARSHALLEDOBJECT exploitable?
How severe is GHSA-LOG4J2-4255-MARSHALLEDOBJECT?
What type of vulnerability is GHSA-LOG4J2-4255-MARSHALLEDOBJECT?
Which versions of org.apache.logging.log4j:log4j-core are affected by GHSA-LOG4J2-4255-MARSHALLEDOBJECT?
Is there a fix for GHSA-LOG4J2-4255-MARSHALLEDOBJECT?
How can I reproduce GHSA-LOG4J2-4255-MARSHALLEDOBJECT?
Is the GHSA-LOG4J2-4255-MARSHALLEDOBJECT reproduction verified?
References for GHSA-LOG4J2-4255-MARSHALLEDOBJECT
Authoritative sources for GHSA-LOG4J2-4255-MARSHALLEDOBJECT — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.