Automated Threat Modeling

Brief Summary: OpenAM CVE-2026-123551 Session Token Disclosure via the Notification WebSocket

A brief summary of CVE-2026-123551, a CVSS 10.0 flaw in OpenAM 14.0.0 through 16.1.3 that lets unauthenticated attackers bypass the agent-only check on the notification WebSocket and collect live iPlanetDirectoryPro session tokens. The post covers the root cause, the 16.1.4 patch, and behavioral detection approaches.

CVE Analysis

11 min read

Gaurav Sarraf
Gaurav Sarraf

2026-11-07

Brief Summary: OpenAM CVE-2026-123551 Session Token Disclosure via the Notification WebSocket
Experimental AI-Generated Content

This CVE analysis is an experimental publication that is completely AI-generated. The content may contain errors or inaccuracies and is subject to change as more information becomes available. We are continuously refining our process.

If you have feedback, questions, or notice any errors, please reach out to us.

[email protected]

Introduction

An unauthenticated attacker who can reach an OpenAM server running 14.0.0 through 16.1.3 can quietly collect live iPlanetDirectoryPro session tokens as users and administrators log in, log out, and time out. Those tokens are bearer credentials accepted by OpenAM REST endpoints and by applications relying on OpenAM single sign-on, so one captured administrator session can lead to configuration takeover and, according to the maintainer, command execution as the OpenAM service account.

OpenAM is an access management server maintained by Open Identity Platform, an independent community project that describes itself as the free, open-source continuation of the identity stack ForgeRock was built on, forked from the last freely licensed releases. It provides single sign-on, authorization policies, more than 20 authentication modules, multifactor and adaptive authentication, and can act as an identity provider over SAML, OAuth 2.0 and OpenID Connect 1.0. The project is CDDL licensed, with no per-user or per-server fees, and independent vendors offer commercial support. That makes it a self-hosted option for organizations leaving ForgeRock, although the available sources do not quantify its installed base.

Technical information

The primary weakness recorded for CVE-2026-123551 is CWE-201, Insertion of Sensitive Information Into Sent Data. The maintainer also identifies authentication bypass, insufficiently protected credentials, open redirect and missing authorization weaknesses. In practice, the bug is a chain: an internal dispatch skips a security filter, a notification channel accepts subscriptions it should refuse, and the data on that channel is a reusable credential.

The credential on the wire

OpenAM publishes session notifications for policy agents. These notifications carry the full iPlanetDirectoryPro session identifier whenever a session is created, logged out, timed out, or has a property changed. That identifier is a bearer credential, so whoever holds it can act as the session owner. Agent notifications are controlled by the advanced server property org.forgerock.openam.notifications.agents.enabled, which is enabled by default. The advisory states that no separate federation, self-service or agent feature configuration is required for exposure, so a deployment that never intentionally installed policy agents is not automatically safe.

Why the agent-only check could be skipped

The /notifications endpoint is protected by NotificationsWebSocketFilter, which is meant to admit only policy agents. The gap comes from Servlet dispatch semantics. Under the Servlet specification, a <filter-mapping> that lists no <dispatcher> element applies only to REQUEST dispatches. When a servlet calls RequestDispatcher.forward() or include(), or when an async or error page dispatch occurs, the container routes straight to the target. As the fix PR puts it, such a dispatch "reaches the servlet with the filter skipped".

A legacy Liberty ID FF endpoint performed exactly that kind of internal forward to a path taken from the request. The forward lives in FSUtils.forwardRequest. Before the patch, it validated the request-derived path with ForwardPathValidator.isSafeForwardPath and then handed the raw path to getRequestDispatcher. That leaves a gap between the string that was checked and the path the container actually resolves, and because the forward is an internal dispatch, the agent-only gate on /notifications never runs.

Unrestricted topic subscriptions

Once connected, a client could subscribe to any topic, including internal ones, not only the agent namespace. Combined with the bypass above, this lets an unauthenticated client receive the session topic and the tokens it carries. The advisory notes the connection "can be kept open indefinitely".

Attack flow

Based on the advisory, the chain looks like this. The maintainer withholds exact request details and proof-of-concept code, so we describe only the documented stages.

  1. Reach the service. The attacker needs network access to the OpenAM port. No credentials or user interaction are required.
  2. Bypass the agent check. The attacker sends a request to a legacy Liberty ID FF endpoint (the advisory names /openam/preLogin and /openam/postLogin among them) that triggers an unvalidated internal forward toward the notification WebSocket. Because the forward is a FORWARD dispatch, NotificationsWebSocketFilter does not execute.
  3. Subscribe to internal topics. With the WebSocket open, the attacker subscribes to the session topic and other internal topics.
  4. Collect tokens passively. Every session creation, logout, timeout and property change broadcasts a full iPlanetDirectoryPro identifier. The attacker simply waits while the connection stays open.
  5. Reuse a captured token. Stolen tokens work against OpenAM REST endpoints and any application relying on OpenAM single sign-on, and the resulting requests look like the legitimate user's own activity.
  6. Escalate if an administrator was captured. A superuser session carries administrative capabilities. The maintainer states this can escalate to configuration takeover and command execution as the OpenAM service account. This is conditional on capturing an administrator session, not unconditional code execution on every reachable server.

The adjacent redirect issue

The same legacy ID FF endpoints also built redirect destinations from request data without validation. Where URL rewriting for cookieless clients is enabled, the user's session token could be appended to a destination on another host. Version 16.1.4 addresses this path as well.

Severity scoring

Two critical assessments have been published, using different CVSS versions:

  • OpenAM maintainer, CVSS 3.1: 10.0, vector CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
  • VulnCheck (CNA), CVSS 4.0: 10.0, vector CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H

NVD displays the VulnCheck score and states that its own assessment has not yet been provided, so the 10.0 should not be read as an independent NVD validation.

Exploitation status

Neither the maintainer advisory nor the VulnCheck advisory reports observed exploitation in the wild, names victims or campaigns, or attributes activity to a threat actor. The maintainer deliberately withholds proof-of-concept code to give operators time to upgrade, which describes the disclosure position rather than proving no exploit exists. The public timeline is: GitHub advisory on October 22, 2026; VulnCheck advisory on November 7, 2026; NVD publication on November 8, 2026. The earlier GitHub advisory still displays "No known CVE" while the CNA and NVD records carry CVE-2026-123551.

Patch information

The fix ships in OpenAM 16.1.4, released October 22, 2026 (tag 16.1.4, release commit f2b13be). No backported fix for older branches has been published. The advisory summarizes the fix as four changes:

  1. Security filters now run on internal dispatches, including the agent-only check on the WebSocket.
  2. The legacy Liberty ID FF endpoints were hardened. They no longer forward requests into OpenAM's internal endpoints, never pass a session token to another host, and only accept destinations from a per-provider allow list.
  3. WebSocket subscriptions are restricted to /agent/ topics.
  4. Session events are still published on the agent session topic, because policy agents depend on it.

The public code for the dispatcher change and the ID FF forward hardening is in PR #1133, "Run the security filters on every dispatch type" (merged September 29, 2026, merge commit 81d8304a, listed in the 16.1.4 release notes). We could not find a separate public commit for the topic allow list or the Relay State allow list, so those two changes are described from the advisory rather than a diff.

1. Filters on every dispatcher type

Four narrowly mapped security filters now run on all five dispatcher types, REQUEST, FORWARD, INCLUDE, ASYNC and ERROR:

  • AuthNFilter on /ws/*
  • AuthZFilter on /ws/*
  • JAXRPCRequestFilter on /jaxrpc/*
  • NotificationsWebSocketFilter on /notifications

An internal forward to the WebSocket endpoint now passes through the same authentication check as a direct request. The PR adds a regression test, SecurityFilterDispatchersTest, that parses the shipped web.xml and fails the build if any of these mappings loses a dispatcher type. Naming even one dispatcher replaces the default set, so without the test a later edit listing only some types would silently reopen the hole.

The maintainers deliberately did not change the filters mapped to /* (amSetupFilter, SecurityHeaders, AuditContextFilter, ResponseValidationFilter) or FQDNValidationFilter, since running those on every internal forward would change behavior across the product. That is left for a separate change.

2. Making JAXRPCRequestFilter reentrant

Because JAXRPCRequestFilter now also runs on FORWARD and INCLUDE, a nested dispatch can enter it twice on the same thread. The old code always cleared its ThreadLocal on exit, which would drop the outer request's binding. The patched code saves and restores the previous binding:

HttpServletRequest previous = CURRENT_REQUEST.get(); CURRENT_REQUEST.set((HttpServletRequest) request); try { chain.doFilter(request, response); } finally { if (previous == null) { CURRENT_REQUEST.remove(); } else { CURRENT_REQUEST.set(previous); } }

A new test, nestedDispatchRestoresTheOuterRequestOnExit, covers this behavior.

3. Tighter checks on the ID FF forward target

FSUtils.forwardRequest now dispatches only the normalized form returned by a new helper, forwardTarget(), and returns HTTP 400 if the helper returns null. The excerpt below is from the patch:

String dispatchPath = ForwardPathValidator.forwardTarget(resource); if (dispatchPath == null) { FSUtils.debug.warning("FSUtils.forwardRequest: refusing to " + "forward to a path with traversal or a reserved " + "directory");

forwardTarget() reconstructs the path the container would map and checks it again:

  • It runs the existing isSafeForwardPath check first.
  • It strips path parameters (;...).
  • It decodes percent escapes in a loop until no % remains, while keeping + literal.
  • It refuses any .. segment and refuses a WEB-INF segment anywhere in the path, not only at the root. For example, /x;a/%57EB-INF/y.jsp is now rejected.
  • It appends the original query string after a fixed ?.

4. Changes described in the advisory only

  • Topic allow-listing: clients can subscribe only to /agent/ topics. Any other topic is refused.
  • ID FF redirect handling: the endpoints no longer redirect to arbitrary request-supplied destinations and no longer append the session token to an off-host URL under cookieless URL rewriting. Destinations must match a new per-provider Relay State URL List.

Upgrade notes

  • Customized web.xml: if you maintain your own web.xml, copy the new dispatcher declarations onto the AuthNFilter, AuthZFilter, JAXRPCRequestFilter and NotificationsWebSocketFilter mappings. If you skip this, the bypass stays open even on 16.1.4 binaries.
  • Empty Relay State URL List: while empty, OpenAM only accepts destinations under the deployment's own URLs. Deployments that send users to another host after ID FF login, federation or logout must add those hosts, otherwise users land on the provider home page or the logout done page.
  • Non-agent topics: any notification client subscribing outside /agent/ will be refused after upgrade.

Interim workarounds and post-exposure steps

While the upgrade is in progress, the advisory documents these measures:

  • Restrict /openam/notifications and /openam/ws/* to legitimate agent hosts at the reverse proxy, load balancer or firewall.
  • Set org.forgerock.openam.notifications.agents.enabled=false where agents do not depend on notifications.
  • Block /openam/preLogin and /openam/postLogin unless Liberty ID FF federation is required.
  • Treat current administrator and user sessions as potentially exposed and rotate them. Upgrading does not invalidate tokens that may already have been collected.
  • Keep Groovy and JavaScript scripting services under the security manager with a restrictive allow list, restrict scripting configuration changes, and run the OpenAM container in an operating system sandbox with a read-only filesystem, no shell and a least-privilege account.
  • Do not expose administrative or agent-facing endpoints to the public internet.

Detection methods

We found no public YARA, Sigma, Snort or Suricata rules and no IoC lists for CVE-2026-123551, and the advisory withholds technical details. Detection therefore rests on behavioral monitoring derived from the vendor's guidance.

The advisory describes the attack as passive: no authentication attempts, no failed logins, no lockouts, and hijacked requests "indistinguishable from the legitimate user's own session activity." Brute-force and login-failure monitoring will not catch it. The useful evidence sits at the start of the chain (reaching and subscribing to the WebSocket) and at the end (a stolen administrator session turned into configuration changes).

1. Allow-list notification WebSocket clients

  • From reverse proxy, load balancer or WAF logs, enumerate hosts that connect to /openam/notifications and /openam/ws/*. These should be policy agent servers only.
  • Alert on any WebSocket upgrade or connection to those paths from outside that list, especially from user- or internet-facing networks.
  • Prioritize long-lived connections. A client that is not a known agent holding a notification socket open for hours is a strong indicator, since tokens are only collected while the connection is open.

2. Watch topic subscriptions

If OpenAM debug logs or a WebSocket-aware proxy record subscription messages, flag:

  • subscriptions to the session topic from any client that is not a known agent
  • subscriptions to topics outside the /agent/ namespace, which the fixed release refuses and which are abnormal on a vulnerable instance

3. Watch legacy Liberty ID FF endpoints

  • Baseline requests to /openam/preLogin, /openam/postLogin and related ID FF paths. In deployments without ID FF, any request deserves review.
  • Correlate these requests with a notification WebSocket connection from the same source around the same time. That pairing fits the documented bypass chain.
  • Review ID FF requests whose destination or relay parameters point to hosts outside your domains, which relates to the token-leaking redirect path when cookieless URL rewriting is enabled.

4. Watch for administrative post-compromise activity

  • Scripting engine changes: alert on any change to the Groovy or JavaScript scripting service configuration, especially loosening of the security manager allow list or new scripts, and reconcile against change tickets.
  • Child processes: treat any process spawned by the OpenAM service account (for example a shell) as high severity.
  • Administrative REST activity: review admin REST calls from IP ranges an administrator never uses, or shortly after a suspicious notification socket was opened.

5. Scope exposure

Inventory OpenAM deployments on 14.0.0 through 16.1.3. Software composition analysis can flag the affected Maven artifacts under org.openidentityplatform.openam. Check whether org.forgerock.openam.notifications.agents.enabled is left at its default of enabled, and whether /openam/notifications or the ID FF endpoints are reachable beyond agent hosts. Because token theft leaves little trace, hunting should include reviewing past session activity, not only new alerts.

Affected systems and versions

  • Product: OpenAM by Open Identity Platform (NVD vendor: OpenIdentityPlatform)
  • Vulnerable: versions 14.0.0 through 16.1.3 (NVD and VulnCheck: 14.0.0 up to, but not including, 16.1.4)
  • Fixed: 16.1.4
  • Affected Maven artifacts (each vulnerable at >= 14.0.0, <= 16.1.3, patched in 16.1.4):
    • openam-server-only
    • openam-federation-library
    • openam-notifications-websocket
  • Vulnerable configuration: agent notifications enabled via org.forgerock.openam.notifications.agents.enabled, which is the default. No separate federation, self-service or agent feature configuration is required.
  • Not affected: releases before 14.0.0, which have no notification WebSocket.
  • Partially fixed risk: 16.1.4 installations using a customized web.xml that lacks the new dispatcher declarations remain exposed to the bypass.
  • Backports: none published for older branches.

Vendor security history

Open Identity Platform has published several substantive security fixes for OpenAM in 2026:

  • OpenAM 16.1.1 addressed LDAP injection, session hijacking via CDSSO and Session Service RPC, and conditional code execution through WebAuthn deserialization. The release notes do not indicate these were exploited in the wild.
  • OpenAM 16.1.4 fixed this notification WebSocket issue alongside acceptance of unsigned SAML v2.0 assertions in some bindings and a self-registration flaw that could let an anonymous user create an administrator account.

The repository publishes a security support policy and asks reporters to open a draft security advisory. The CVE record credits DauHoangTai as reporter, maximthomas as remediation developer, and tsujiguchitky and vharseko as remediation reviewers. The sources do not establish discovery-to-patch times or independent audit results, so we draw no conclusion on response speed.

References

Detect & fix
what others miss

Works with
  • GitHub
  • GitLab
  • Bitbucket
  • Azure DevOps Services
  • Gerrit
  • CVS
  • Jira
  • Linear
  • Slack
  • Security Compass
Explore integrations
Security magnifying glass visualization