U-Sec commented on issue #4255: URL: https://github.com/apache/logging-log4j2/issues/4255#issuecomment-5393493255
**Follow-up from the reporter — two refinements to the original report.** ## 1. Correction: global `jdk.serialFilter` DOES defend (when configured), and this yields an immediate workaround The original report states the `MarshalledObject` ObjectInputFilter capture is a no-op because FOIS never calls `setObjectInputFilter()`. That is only true when **no process-wide filter is configured** (the JDK default, i.e. most deployments). We re-ran the full PoC matrix against OpenJDK 17.0.18 with global filters enabled: | Global `jdk.serialFilter` | Result | |---|---| | *none configured* (JDK default) | **Exploit succeeds** — unfiltered inner stream | | `maxdepth=5;maxbytes=1000000` (commonly recommended generic filter) | **Exploit still succeeds.** The inner stream inside `MarshalledObject.get()` is a *new* stream: depth counting restarts and the payload is only ~1.3 KB / depth 2, so generic depth/byte limits do not stop it | | `!java.rmi.MarshalledObject` | Blocked at the outer stream (`InvalidClassException: REJECTED`) | | `!com.example.GadgetClass` (deny a gadget class) | Blocked at the inner stream — **and silently**: the receiver logs the event normally (`message()` falls back to `SimpleMessage`), so probing attempts leave no trace | | allowlist without `MarshalledObject` | Blocked | Technical explanation: each `ObjectInputStream` constructor inherits the process-wide filter, so the filter captured by `MarshalledObject.readObject` is the *global* one, not null. Class-pattern filters therefore apply to both layers; generic depth/size filters only apply per-stream. **Immediate operator workaround (no code change needed):** ``` -Djdk.serialFilter='!java.rmi.MarshalledObject' ``` or any class-pattern allowlist that omits `java.rmi.MarshalledObject` / denies known gadget classes. This closes the receiver path until a library fix ships. ## 2. Additional hardening gap: FOIS does not override `resolveProxyClass` `FilteredObjectInputStream` only overrides `resolveClass()` (line 66). Serialized `TC_PROXYCLASS` descriptors are resolved by the default `resolveProxyClass()` implementation, so **the proxy interface names never pass through the allowlist**. For comparison, Tomcat's `CustomObjectInputStream` performs its `checkAllowed()` in both `resolveClass` and `resolveProxyClass`. Standalone exploitation is constrained (no dangerous `InvocationHandler` is present on the default allowlist), so we do not consider this an independent RCE — but it is a second, independent allowlist gap and should be fixed alongside: override `resolveProxyClass` to run the same allowlist check on every interface name in `interfaces[]`. Both refinements have been re-verified against the official 2.26.1 artifacts; the PoCs are available to maintainers on request. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
