First publicly shared exploit implementation for CVE-2026-33439 (OpenAM pre-auth RCE via jato.clientSession deserialization).
Human insight + AI-assisted analysis + reverse engineering + advisory → exploit
First publicly shared exploit implementation for CVE-2026-33439
Unauthenticated Java deserialization vulnerability in ForgeRock OpenAM allowing full remote code execution via crafted JATO session objects. The same river flows twice, they fixed jato.pageSession (CVE-2021-35464) and forgot jato.clientSession (CVE-2026-33439). A deserialization gadget chain does not ask for credentials.
CVE-2026-33439 is a pre-authentication Remote Code Execution vulnerability in OpenIdentityPlatform OpenAM (versions prior to 16.0.6). The vulnerability stems from unsafe Java deserialization of the jato.clientSession HTTP parameter inside ClientSession.deserializeAttributes(), which calls Encoder.deserialize() → ApplicationObjectInputStream.readObject() with no class whitelist applied.
An unauthenticated attacker sends a crafted HTTP GET or POST request containing a serialized Java object to any JATO ViewBean endpoint whose JSP renders <jato:form> tags. Upon receipt, the server deserializes the object without validation, triggering a gadget chain built entirely from classes bundled in the OpenAM WAR - no external libraries required - and executing arbitrary OS commands as the application process user.
CVSS 4.0 Vector: AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N → 9.3 Critical
CVSS 3.1 Vector: AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H → 9.8 Critical
This vulnerability is a direct regression of the incomplete fix applied after CVE-2021-35464.
CVE-2021-35464 (ForgeRock AM / OpenAM): Pre-auth RCE via unsafe deserialization of the jato.pageSession parameter. Widely exploited in the wild; CISA KEV-listed. The fix introduced WhitelistObjectInputStream inside ConsoleViewBeanBase.deserializePageAttributes() - a custom ObjectInputStream subclass that checks every class name against a hardcoded allowlist of ~40 safe classes before instantiating it.
CVE-2026-33439 (OpenAM ≤ 16.0.5): The fix was applied to jato.pageSession only. The jato.clientSession parameter - handled by a completely separate code path in ClientSession.deserializeAttributes() - was never patched and still uses the unfiltered Encoder.deserialize() → ApplicationObjectInputStream, which calls ObjectInputStream.readObject() with no class whitelist.
The attack primitive is the same. The deserialization sink is different. Only the parameter name changed.
JATO serializes UI view state to HTTP parameters named jato.pageSession and jato.clientSession. When a request arrives, OpenAM deserializes these parameters to restore UI state before rendering the response. The two parameters follow entirely different code paths.
The patched code path (post-CVE-2021-35464) for jato.pageSession:
// PATCHED - ConsoleViewBeanBase.deserializePageAttributes()
ObjectInputStream ois = new WhitelistObjectInputStream(new ByteArrayInputStream(decoded));
// class whitelist enforced - gadget chains blocked
Object obj = ois.readObject();
The unpatched code path for jato.clientSession (vulnerable):
// ClientSession.java
protected ClientSession(RequestContext context) {
this.encodedSessionString =
context.getRequest().getParameter("jato.clientSession");
}
protected void deserializeAttributes() {
if (this.encodedSessionString != null
&& this.encodedSessionString.trim().length() > 0) {
this.setAttributes(
(Map) Encoder.deserialize(
// VULNERABLE - URL-safe base64 decode then plain ObjectInputStream
Encoder.decodeHttp64(this.encodedSessionString), false)
);
}
}
Encoder.deserialize() constructs a plain ApplicationObjectInputStream - a subclass of ObjectInputStream with no class filtering. Any class on the JVM classpath can be instantiated. Deserialization is triggered during JSP rendering whenever a < jato:form > tag is rendered:
getClientSession() → hasAttributes() → getEncodedString() → isValid() → ensureAttributes() → deserializeAttributes()
| Product | Vulnerable | Fixed |
|---|---|---|
| OpenIdentityPlatform OpenAM | ≤ 16.0.5 | 16.0.6 |
| ForgeRock AM (downstream) | Potentially affected depending on patch lineage | - |
Any JATO ViewBean endpoint whose JSP contains a < jato:form > tag is exploitable pre-authentication:
| Endpoint | Purpose |
|---|---|
| /ui/PWResetUserValidation | Password reset - user identity input |
| /ui/PWResetQuestion | Password reset - security questions |
Password reset endpoints are the primary target, they are publicly accessible by design and guaranteed to render < jato:form > tags.
When Java deserializes an object from a byte stream, it calls readObject() on every class it reconstructs, including nested objects. If an attacker controls the byte stream and injects an object whose readObject() triggers a chain of method calls ending in code execution, they have gadget-chain RCE.