GitHub Security Advisory: GHSA-2cqq-rpvq-g5qj
Package: org.openidentityplatform.openam:openam (MAVEN)
Severity: CRITICAL (CVSS 0.0)
CWE: CWE-502: Deserialization of Untrusted Data
Vulnerable versions: <= 16.0.5
Patched in: 16.0.6

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

Details:
## Summary

OpenIdentityPlatform OpenAM 16.0.5 (and likely earlier versions) is vulnerable to pre-authentication Remote Code Execution (RCE) via unsafe Java deserialization of the `jato.clientSession` HTTP parameter. This bypasses the `WhitelistObjectInputStream` mitigation that was applied to the `jato.pageSession` parameter after CVE-2021-35464.

An unauthenticated attacker can achieve arbitrary command execution on the server by sending a crafted serialized Java object as the `jato.clientSession` GET/POST parameter to any JATO ViewBean endpoint whose JSP contains `<jato:form>` tags (e.g., the Password Reset pages).

---

## Vulnerability Details

### Background

CVE-2021-35464 identified that the `jato.pageSession` HTTP parameter was deserialized without class filtering, allowing pre-auth RCE.

OpenIdentityPlatform OpenAM mitigated this by introducing `WhitelistObjectInputStream` in `ConsoleViewBeanBase.deserializePageAttributes()`, which restricts `jato.pageSession` deserialization to a hardcoded whitelist of ~40 safe classes.

However, the JATO framework contains a **second deserialization entry point** — `jato.clientSession` — handled by `ClientSession.deserializeAttributes()`. This code path was **not patched** and still uses the unfiltered `Encoder.deserialize()` → `ApplicationObjectInputStream`, which performs `ObjectInputStream.readObject()` with no class whitelist.

### Root Cause

```
ClientSession.deserializeAttributes()
  → Encoder.deserialize()
    → ApplicationObjectInputStream.readObject()  // VULNERABLE — no whitelist
```

The `ClientSession` object is instantiated in `RequestContextImpl.getClientSession()` with the raw `jato.clientSession` parameter value from the HTTP request. Deserialization is triggered during JSP rendering when `<jato:form>` tags invoke `getClientSession()` → `hasAttributes()` → `getEncodedString()` → `isValid()` → `ensureAttributes()` → `deserializeAttributes()`.

### Affected Code

**File:** `com/iplanet/jato/ClientSession.java`
```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(
                Encoder.decodeHttp64(this.encodedSessionString), false)
        );
    }
}
```

### Gadget Chain

The exploit uses classes bundled in the OpenAM WAR:

```
PriorityQueue.readObject()                        [java.util — JDK]
  → heapify() → siftDown() → comparator.compare()
    → Column$ColumnComparator.compare()            [openam-core-16.0.5.jar]
      → Column.getProperty()
        → PropertyUtils.getObjectPropertyValue()   [openam-core-16.0.5.jar]
          → Method.invoke(TemplatesImpl, "getOutputProperties")
            → TemplatesImpl.getOutputProperties()  [xalan-2.7.3.jar]
              → newTrans