Vol de jetons de session et contournement SAML dans OpenAM (CVE-2026-123551)
OpenAM avant 16.1.4 laisse fuir des jetons de session et accepte des assertions SAML non signées, permettant des détournements de session ; corrigé dans 16.1.4.
En bref
- OpenAM avant 16.1.4 diffuse des jetons de session en clair vers les topics des agents de stratégie et accepte des assertions SAML non signées sur les liaisons ECP et HTTP-Artifact. Un attaquant non authentifié peut exploiter l'une ou l'autre faille pour détourner des sessions d'utilisateurs et d'administrateurs.
- La même version corrige une faille d'auto-inscription qui permet à un utilisateur anonyme de rejoindre un groupe d'administration. OpenIdentityPlatform a publié les avis et OpenAM 16.1.4 le 2026-10-22.
- Les enregistrements CVE notent la divulgation de jetons CVSS v4.0 10,0 et les deux autres failles 9,3. Les avis du fournisseur notent la faille de jetons CVSS v3.1 10,0 et les deux autres 9,8.
- Aucune preuve de concept publique ni exploitation en environnements réels n'est signalée. Les failles ne figurent pas dans le catalogue KEV de la CISA au 2026-11-08. Passez à OpenAM 16.1.4.
Suis-je concerné ?
Toutes ces conditions doivent être réunies :
- Vous exécutez OpenIdentityPlatform OpenAM dans une version antérieure à 16.1.4.
- Pour la faille de jetons de session, vous exécutez une version 14.0.0 à 16.1.3 et le WebSocket de notification est joignable. Les notifications d'agents sont activées par défaut, et c'est ce qui place les identifiants de session sur les topics des agents.
- Pour la faille SAML, OpenAM agit comme fournisseur de service SAML v2.0 hébergé. Ses métadonnées annoncent le service de consommation d'assertions ECP (PAOS), ce que font les métadonnées générées par défaut. Le fournisseur de service a
WantAssertionsSignedà false, ce que font aussi les métadonnées générées par défaut, et une clé de chiffrement configurée pour que les fournisseurs d'identité puissent lui chiffrer des assertions. - Pour la faille d'auto-inscription, l'auto-inscription est activée dans le realm. Elle est désactivée par défaut.
| Branche | Versions concernées | Version corrigée |
|---|---|---|
| OpenAM 14.0.0 à 16.1.3 | Les trois failles | 16.1.4 (2026-10-22) |
| OpenAM avant 14.0.0 | Contournement d'assertion SAML et escalade par auto-inscription ; le WebSocket de notification n'existe pas | 16.1.4 (2026-10-22) |
Le point de terminaison de version répond sans session. Interrogez le serveur directement :
curl -s https://openam.example.com:8443/openam/json/serverinfo/version
La réponse contient version, revision et date. Dans l'image conteneur, la même requête vise le port local :
docker exec openam curl -s http://localhost:8080/openam/json/serverinfo/version
Comment corriger ?
Passez à OpenAM 16.1.4 ou une version ultérieure. Le fournisseur l'a publié le 2026-10-22, le même jour que les avis.
- Pour l'image conteneur, définissez le service sur
openidentityplatform/openam:16.1.4dans votre fichier Compose. Téléchargez l'image configurée et recréez le conteneur :
docker compose pull openam
docker compose up -d openam
-
Pour un déploiement WAR, téléchargez
openam-server-only16.1.4 depuis Maven Central et déployez le nouveauopenam.warpar-dessus l'application web existante. Redémarrez le conteneur après le déploiement. -
Pour un build Maven qui dépend des artefacts OpenAM, fixez
org.openidentityplatform.openam:openam-server-onlyet les autres modules OpenAM à16.1.4.
Si vous ne pouvez pas mettre à jour immédiatement, ces mesures réduisent l'exposition mais ne corrigent pas le code :
- Passez
WantAssertionsSignedà true sur chaque fournisseur de service SAML v2.0 hébergé et activez la signature des réponses. Cela couvre la faille d'assertion. Cela ne couvre ni le WebSocket de notification ni l'auto-inscription. - Restreignez le WebSocket
/openam/notificationset les points de terminaison Liberty ID-FF hérités aux hôtes des agents de stratégie, au niveau du proxy inverse ou du réseau. Cela réduit le chemin de divulgation des jetons. Cela n'arrête pas un attaquant qui peut joindre ces points de terminaison par une autre route. - Désactivez l'auto-inscription dans chaque realm. Cela ferme uniquement le chemin d'inscription anonyme.
- Considérez chaque instance OpenAM exposée à Internet avant la mise à jour comme exposée, et vérifiez ses sessions et ses administrateurs après la mise à jour.
Quelle est la cause racine ?
OpenAM n'appliquait l'héritage de signature SAML que sur la liaison HTTP-POST. Toutes les autres liaisons dépendaient d'un indicateur de métadonnées que les métadonnées générées du fournisseur de service mettent à false. La vérification se trouve dans SAML2Utils.verifyResponse, dans la bibliothèque de fédération, dans OpenAM 16.1.3 :
if (wantAssertionsSigned && !(responseIsSigned || allAssertionsSigned)) {
throw new SAML2Exception(bundle.getString("assertionNotSigned"));
}
if (profileBinding.equals(SAML2Constants.HTTP_POST)) {
boolean wantPostResponseSigned = SAML2Utils
.wantPOSTResponseSigned(orgName, hostEntityId, SAML2Constants.SP_ROLE);
if (wantPostResponseSigned && !responseIsSigned) {
throw new SAML2Exception(bundle.getString("responseNotSigned"));
}
if (!responseIsSigned && !allAssertionsSigned) {
throw new SAML2Exception(bundle.getString("assertionNotSigned"));
}
}
Le premier bloc ne rejette une réponse non signée que si les métadonnées WantAssertionsSigned du fournisseur de service sont à true. Le second bloc rejette une réponse non signée ou des assertions non signées quel que soit cet indicateur, mais il ne s'exécute que pour HTTP_POST. Sur les liaisons ECP (PAOS) et HTTP-Artifact, aucun des deux blocs n'exige de signature si l'indicateur de métadonnées est désactivé.
Le WebSocket de notification faisait confiance au conteneur pour exécuter son filtre, et le filtre n'était mappé que sur les dispatches de requête. Le gestionnaire du WebSocket abonnait le client à n'importe quel topic qu'il nommait :
String topic = json.get("topic").asString();
subscription.bindTo(Topic.of(topic));
Le filtre de sécurité lit le cookie d'agent et vérifie que le jeton appartient à un agent de stratégie J2EE ou web. Dans OpenAM 16.1.3, son mapping dans web.xml ne nommait aucun dispatcher, donc le conteneur ne l'exécutait que sur les dispatches REQUEST.
Un transfert interne vers /notifications arrive comme un dispatch FORWARD. Le filtre était ignoré, et la mise à niveau WebSocket se poursuivait sans la vérification d'agent. Les points de terminaison Liberty ID-FF hérités d'OpenAM effectuent de tels transferts. L'avis cite un transfert interne non validé comme moyen d'atteindre le socket sans identifiants.
L'action d'auto-inscription anonyme créait le compte avec le jeton de l'administrateur système. Elle n'appliquait jamais la liste d'attributs autorisés. Dans IdentityResourceV2.anonymousCreate en 16.1.3, le corps de la requête allait directement au service d'identité :
SSOToken admin = RestUtils.getToken();
return createInstance(admin, jVal, realm, context, null)
La liste autorisée vivait dans IdentityRestUtils et ne s'appliquait qu'aux requêtes portant un SelfServiceContext. L'action héritée n'en porte aucun, donc un appelant pouvait définir n'importe quel attribut. Une valeur memberof ne reste pas un attribut : la couche d'identité la transforme en appartenance à un groupe. Un utilisateur qui s'auto-inscrit pouvait donc rejoindre un groupe d'administration.
Comment la faille est-elle exploitée ?
Le chemin SAML ne demande ni identifiants ni interaction de l'utilisateur :
- L'attaquant trouve un fournisseur de service SAML v2.0 hébergé sur une instance OpenAM concernée. Il annonce ECP (PAOS), a
WantAssertionsSigneddésactivé et une clé de chiffrement configurée. - L'attaquant construit une réponse SAML avec une assertion qui nomme un compte cible, y compris un administrateur, et l'envoie au point de terminaison ECP ou HTTP-Artifact sans signature.
- OpenAM vérifie l'émetteur par rapport au cercle de confiance, mais pas la signature sur cette liaison. Il associe l'assertion au compte local et émet une session.
- L'attaquant utilise cette session contre OpenAM et contre chaque application qui s'appuie sur lui pour l'authentification unique.
Le chemin de notification demande une route vers le WebSocket :
- L'attaquant envoie une requête à un point de terminaison Liberty ID-FF hérité qui transfère en interne vers
/notifications. Le transfert ignore le filtre qui vérifie le jeton d'agent de stratégie. - L'attaquant s'abonne à un topic interne. Avant le correctif, le gestionnaire acceptait n'importe quel nom de topic.
- OpenAM publie la valeur complète
iPlanetDirectoryProà la création, à la déconnexion, à l'expiration et au changement de propriété d'une session, car les notifications d'agents sont activées par défaut. - L'attaquant rejoue une valeur capturée comme identifiant porteur contre les points de terminaison REST d'OpenAM et contre les applications qui font confiance à la même session.
Le chemin d'auto-inscription demande que l'auto-inscription soit activée :
- L'attaquant termine la vérification par courriel pour une adresse qu'il contrôle.
- L'attaquant envoie l'action
anonymousCreateavec une valeurmemberofqui nomme un groupe d'administration. - OpenAM crée le compte avec son jeton d'administrateur système et écrit l'appartenance au groupe. Le nouveau compte peut administrer le realm.
Aucune preuve de concept publique n'existe pour l'une des trois failles. Les avis indiquent que les détails techniques et le code de preuve de concept sont retenus pour laisser aux opérateurs le temps de mettre à jour.
Comment se déroule l'attaque ?
Une assertion SAML non signée atteint un fournisseur de service qui ne vérifie les signatures que sur une autre liaison, s'associe à un compte local et devient une session pour chaque application derrière OpenAM.
SAML non signée"] --> B["L'envoie au point de terminaison
ECP ou HTTP-Artifact"] B --> C["Le SP vérifie la signature
uniquement sur HTTP-POST"] C --> D["aucune vérification de signature
sur cette liaison"] D --> E["L'assertion correspond à un utilisateur local,
y compris un administrateur"] E --> F["OpenAM émet une session"] F --> G["L'attaquant atteint chaque
application qui fait confiance à OpenAM"]
Que peut faire un attaquant ?
La faille SAML permet à un attaquant non authentifié d'obtenir une session pour n'importe quel compte que le fournisseur de service peut associer, y compris un administrateur. Les comptes joignables dépendent du mapping.
L'auto-fédération ou un NameID utilisé comme identifiant utilisateur atteint n'importe quel compte. Un identifiant de fédération qui est une adresse courriel ou un nom d'utilisateur atteint tout compte dont l'attaquant connaît ou peut deviner l'identifiant. L'attaquant hérite de chaque application qui fait confiance à la session détournée.
La faille de notification permet à un attaquant non authentifié de lire le jeton de session en cours de chaque utilisateur dont la session est créée, modifiée ou terminée pendant que la connexion WebSocket est ouverte. Cela inclut les administrateurs. Un jeton est un identifiant porteur contre l'API REST d'OpenAM et contre chaque application derrière la même session. L'attaquant peut aussi s'abonner à des topics internes.
La faille d'auto-inscription permet à un attaquant anonyme de créer un compte membre de n'importe quel groupe existant, y compris un groupe d'administration. Là où un tel groupe existe, le résultat est le contrôle administratif complet du realm. L'attaquant doit avoir l'auto-inscription activée, ce qui n'est pas la configuration par défaut.
Les trois enregistrements CVE notent chaque faille comme critique : CVSS v4.0 10,0 pour la divulgation de jetons et 9,3 pour les deux autres.
Aucune des trois failles n'exige une position locale. Les failles SAML et de notification sont joignables par le réseau. La faille d'auto-inscription est joignable par le réseau lorsque la fonction est activée.
Pourquoi le correctif fonctionne-t-il ?
Le correctif SAML place la décision de signature avant toutes les autres vérifications et l'applique à chaque liaison. Le commit ajoute isMissingRequiredSignature. Il rejette une réponse lorsque ni la réponse ni toutes ses assertions ne sont signées, sauf si la liaison est la liaison HTTP-Artifact dorsale et que sa configuration l'autorise. L'extrait est réduit à cette vérification et à son exception :
+boolean allAssertionsSigned = true;
+List<String> unsignedAssertionIDs = new ArrayList<>();
+for (Assertion assertion : assertions) {
+ if (!assertion.isSigned()) {
+ allAssertionsSigned = false;
+ unsignedAssertionIDs.add(assertion.getID());
+ }
+}
+if (isMissingRequiredSignature(responseIsSigned, allAssertionsSigned,
+ () -> isAssertionSignatureRequired(wantAssertionsSigned, profileBinding, spConfig, orgName,
+ hostEntityId))) {
+ throw new SAML2Exception(bundle.getString("assertionNotSigned"));
+}
Le même commit lie une réponse HTTP-Artifact au fournisseur d'identité qui a résolu l'artefact, afin qu'un partenaire de confiance ne puisse pas répondre avec une réponse émise au nom d'un autre partenaire. Le correctif est complet pour le chemin de réponse du fournisseur de service décrit par les avis.
Le correctif du WebSocket ajoute une liste autorisée de topics et fait exécuter le filtre sur tous les types de dispatch :
+private static final String ALLOWED_TOPIC_PREFIX = "/agent/";
+if (!topic.startsWith(ALLOWED_TOPIC_PREFIX)) {
+ sendError(session, id, "topic not permitted");
+ return;
+}
<filter-mapping>
<filter-name>NotificationsWebSocketFilter</filter-name>
<url-pattern>/notifications</url-pattern>
+ <dispatcher>REQUEST</dispatcher>
+ <dispatcher>FORWARD</dispatcher>
+ <dispatcher>INCLUDE</dispatcher>
+ <dispatcher>ASYNC</dispatcher>
+ <dispatcher>ERROR</dispatcher>
</filter-mapping>
Le code de fédération refuse aussi un transfert vers une racine qui porte un filtre limité aux requêtes. Le correctif couvre les deux moyens décrits par l'avis pour atteindre le socket.
Le correctif d'auto-inscription applique explicitement la liste autorisée, hors de tout SelfServiceContext :
+if (!USER_TYPE.equals(objectType)) {
+ throw new BadRequestException("Self-registration is only supported for users");
+}
+removeIgnoringCase(jVal, EMAIL);
+removeIgnoringCase(jVal, FIELD_MAIL);
+jVal.put(FIELD_MAIL, email);
+enforceSelfRegistrationWhiteList(configHandler, realm, jVal, objectType);
La vérification de la liste autorisée rejette aussi une appartenance à un groupe non autorisée, compare les noms d'attributs sans tenir compte de la casse et refuse un corps qu'elle ne peut pas convertir. L'identité est toujours créée avec le jeton d'administrateur, mais uniquement avec les attributs que la liste autorise.
Comment vérifier si j'ai été compromis ?
Aucun indicateur de compromission n'est publié, et les avis indiquent qu'aucune exploitation n'a été signalée. Considérez ces indices comme des pistes, pas comme des preuves, et notez qu'une tentative échouée peut ne laisser aucune trace.
Vérifiez d'abord la version, car toutes les autres vérifications en dépendent. Cherchez ensuite des sessions créées via les points de terminaison de fédération sans connexion correspondante au fournisseur d'identité. Cherchez aussi des comptes créés par auto-inscription qui sont membres de groupes d'administration, et des connexions WebSocket à /openam/notifications depuis des hôtes qui ne sont pas des agents de stratégie.
Les journaux d'accès du proxy inverse enregistrent le chemin du WebSocket :
grep -iE "GET /openam/notifications|anonymousCreate" /var/log/nginx/access.log
Le journal d'audit d'OpenAM enregistre les événements d'identité et de session au format JSON. Cherchez les créations d'identité et les événements de session autour de la période étudiée :
grep -hE '"eventName": ?"AM-(IDENTITY|SESSION)"' /path/to/openam/audit/*.json | tail -n 200
Si le journal d'audit n'est pas activé, activez-le avant la mise à jour et conservez les journaux existants. Un jeton de session capturé avant une déconnexion reste utilisable jusqu'à son expiration. Révoquez les sessions actives après la mise à jour si vous avez une raison de soupçonner une exposition.
Chronologie
- 2026-10-21 : OpenAM commite les correctifs des failles SAML, WebSocket de notification et auto-inscription.
- 2026-10-22 : OpenAM 16.1.4 est publié et les trois avis sont publiés.
- 2026-11-08 : les enregistrements CVE sont publiés par VulnCheck, et la base d'avis GitHub les liste.
FAQ
Cela concerne-t-il ForgeRock AM ou un autre fork d'OpenAM ?
Les avis couvrent OpenIdentityPlatform OpenAM. Ils ne nomment ni ForgeRock AM ni un autre fork. Si vous exécutez un autre fork, demandez à son fournisseur si les mêmes correctifs sont présents avant de vous fier à cet avis.
16.1.4 suffit-il ?
Oui. OpenAM 16.1.4 contient les correctifs des trois failles, et le fournisseur l'a publié le même jour que les avis. Utilisez 16.1.4 ou une version ultérieure.
Suis-je concerné si je n'utilise pas SAML ?
Peut-être. La faille du WebSocket de notification concerne OpenAM 14.0.0 à 16.1.3 indépendamment de SAML, et la faille d'auto-inscription s'applique partout où l'auto-inscription est activée. Vérifiez la version et les réglages des fonctionnalités.
Existe-t-il des exploits publics ?
Aucune preuve de concept publique n'est publiée pour l'une des trois failles. Les avis retiennent les détails techniques et le code d'exploitation pour laisser aux opérateurs le temps de mettre à jour. Les failles ne figurent pas dans le catalogue KEV de la CISA au 2026-11-08.
Puis-je atténuer sans mettre à jour ?
Seulement en partie. Passer WantAssertionsSigned à true, désactiver l'auto-inscription et restreindre /openam/notifications ferme chaque fois un chemin, mais aucun ne corrige le code. Passez à 16.1.4 dès que possible.
Pourquoi les enregistrements CVE sont-ils apparus après la version corrigée ?
Le fournisseur a publié les avis avec la version 16.1.4 le 2026-10-22. VulnCheck a attribué et publié les enregistrements CVE le 2026-11-08, date à laquelle les scanners qui ne lisent que les flux CVE pouvaient signaler les versions pour la première fois.
Trouvez les serveurs OpenAM exposés avec Ostorlab
La découverte de surface d'attaque d'Ostorlab recense vos hôtes exposés sur Internet. Vous voyez ainsi quels déploiements OpenAM sont exposés et lesquels mettre à jour en priorité. Elle montre les services exposés, pas si une instance donnée est vulnérable.
Références
- Avis OpenIdentityPlatform GHSA-5c3q-hp86-xjr8, « OpenAM: unauthenticated disclosure of live session tokens via the notification WebSocket », CVSS v3.1 10.0, versions 14.0.0 à 16.1.3, corrigé dans 16.1.4 : https://github.com/OpenIdentityPlatform/OpenAM/security/advisories/GHSA-5c3q-hp86-xjr8 (consulté le 8 novembre 2026)
- Avis OpenIdentityPlatform GHSA-3j2f-qhrc-rjfj, « OpenAM: SAML v2.0 service provider accepts unsigned assertions on some bindings », CVSS v3.1 9.8, corrigé dans 16.1.4 : https://github.com/OpenIdentityPlatform/OpenAM/security/advisories/GHSA-3j2f-qhrc-rjfj (consulté le 8 novembre 2026)
- Avis OpenIdentityPlatform GHSA-jv8f-m88g-h6mm, « OpenAM: self-registration does not enforce the allowed attribute list », CVSS v3.1 9.8, corrigé dans 16.1.4 : https://github.com/OpenIdentityPlatform/OpenAM/security/advisories/GHSA-jv8f-m88g-h6mm (consulté le 8 novembre 2026)
- Enregistrement CVE-2026-123551, divulgation de jetons de session, CVSS v4.0 10.0 et v3.1 10.0 : https://www.cve.org/CVERecord?id=CVE-2026-123551 (consulté le 8 novembre 2026)
- Enregistrement CVE-2026-123550, contournement d'assertion SAML, CVSS v4.0 9.3 et v3.1 9.8 : https://www.cve.org/CVERecord?id=CVE-2026-123550 (consulté le 8 novembre 2026)
- Enregistrement CVE-2026-123549, escalade par auto-inscription, CVSS v4.0 9.3 et v3.1 9.8 : https://www.cve.org/CVERecord?id=CVE-2026-123549 (consulté le 8 novembre 2026)
- Commit de correction de la faille SAML, 3bf8e61a7e, 2026-10-21 : https://github.com/OpenIdentityPlatform/OpenAM/commit/3bf8e61a7e (consulté le 8 novembre 2026)
- Commit de correction du WebSocket de notification, 7d6a031c8e, 2026-10-21 : https://github.com/OpenIdentityPlatform/OpenAM/commit/7d6a031c8e (consulté le 8 novembre 2026)
- Commit de correction de l'auto-inscription, 4c8a33822a, 2026-10-21 : https://github.com/OpenIdentityPlatform/OpenAM/commit/4c8a33822a (consulté le 8 novembre 2026)
- Publication OpenAM 16.1.4, 2026-10-22 : https://github.com/OpenIdentityPlatform/OpenAM/releases/tag/16.1.4 (consulté le 8 novembre 2026)
SAML2Utils.javad'OpenAM 16.1.3, la logique de signature vulnérable : https://github.com/OpenIdentityPlatform/OpenAM/blob/16.1.3/openam-federation/openam-federation-library/src/main/java/com/sun/identity/saml2/common/SAML2Utils.java (consulté le 8 novembre 2026)web.xmld'OpenAM 16.1.3, le mapping de filtre sans dispatcher : https://github.com/OpenIdentityPlatform/OpenAM/blob/16.1.3/openam-server-only/src/main/webapp/WEB-INF/web.xml (consulté le 8 novembre 2026)ServerVersionResourced'OpenAM, le point de terminaison de version non authentifié : https://github.com/OpenIdentityPlatform/OpenAM/blob/16.1.4/openam-core-rest/src/main/java/org/forgerock/openam/core/rest/server/ServerVersionResource.java (consulté le 8 novembre 2026)- Catalogue des vulnérabilités exploitées de la CISA, version 2026.11.06, aucune entrée OpenAM : https://www.cisa.gov/known-exploited-vulnerabilities-catalog (consulté le 8 novembre 2026)
- Chiffres de portée du dépôt OpenAM, 902 étoiles et 474 791 téléchargements Docker Hub : https://github.com/OpenIdentityPlatform/OpenAM et https://hub.docker.com/r/openidentityplatform/openam (consulté le 8 novembre 2026)
- Source de la figure 1, les trois commits de correction et la publication 16.1.4 : https://github.com/OpenIdentityPlatform/OpenAM/compare/16.1.3...16.1.4 (consulté le 8 novembre 2026)