# OpenIdentityPlatform OpenAM: Pre-Authentication Remote Code Execution via `jato.clientSession` Deserialization in OpenAM

Unpatched jato.clientSession parameter in OpenAM is deserialized without a class whitelist, letting unauthenticated attackers run arbitrary OS commands via a gadget chain.

- Payout: Research
- Severity: critical
- Program: OpenIdentityPlatform OpenAM
- Found by: iamnoooob
- Disclosed: 2026-04-07
- CVE: CVE-2026-33439
- Write-up quality: 8/10
- Original: https://github.com/advisories/GHSA-2cqq-rpvq-g5qj
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-2cqq-rpvq-g5qj
- Tags: area:web domain:web impact:internal-access impact:rce kind:research platform:ghsa sev:critical tech:java technique:incomplete-fix technique:source-review vuln:deserialization vuln:rce

**Target:** JATO ViewBean JSP endpoints rendering <jato:form> (e.g. Password Reset)
**Root cause:** ClientSession.deserializeAttributes() passes the raw jato.clientSession parameter to Encoder.deserialize()/ApplicationObjectInputStream.readObject() with no class whitelist, unlike the patched jato.pageSession path.
**Steps:**
1. Identify a JATO endpoint whose JSP renders `<jato:form>` tags (e.g. Password Reset page).
2. Build a serialized Java gadget chain: `PriorityQueue` → `Column$ColumnComparator.compare()` → `Column.getProperty()` → `PropertyUtils.getObjectPropertyValue()` → `TemplatesImpl.getOutputProperties()` → `defineTransletClasses()` → attacker translet `<clinit>` → `Runtime.getRuntime().exec(cmd)`.
3. Encode the serialized payload with `Encoder.encodeHttp64` and send it as the `jato.clientSession` GET/POST parameter to the endpoint.
4. Deserialization triggers during JSP rendering when `<jato:form>` calls `getClientSession()` → `hasAttributes()` → `getEncodedString()` → `isValid()` → `ensureAttributes()` → `deserializeAttributes()`, executing the command.
**How found:** After CVE-2021-35464 was mitigated by whitelisting jato.pageSession in ConsoleViewBeanBase.deserializePageAttributes(), researchers audited other callers of Encoder.deserialize() and found the parallel jato.clientSession path in ClientSession.deserializeAttributes() still unfiltered.
**Exploitation:** Unauthenticated attacker sends a crafted Http64-encoded serialized object in the jato.clientSession parameter to any accessible JATO endpoint rendering <jato:form>; the gadget chain fires during JSP rendering and executes arbitrary OS commands as the app server user.
**Insight:** When a deserialization sink is patched by whitelisting one parameter, enumerate sibling parameters handled by the same framework (here jato.pageSession vs jato.clientSession) and audit every caller of the underlying Encoder.deserialize() for the same unfiltered ObjectInputStream.

