
Recherchez des traces d'exploitation de CVE-2026-18963 (prise de contrôle de compte non authentifiée dans Keycloak) dans la base de données Keycloak.
Un script psql qui recherche dans une base de données PostgreSQL Keycloak les traces d'exploitation de la CVE-2026-18963 (prise de contrôle de compte non authentifiée via le flux de réinitialisation des identifiants).
Publié par KYOS. Nous l'avons écrit pendant le correctif des déploiements Keycloak que nous exploitons, afin de vérifier que personne n'avait été compromis pendant la fenêtre d'exposition.
CVE-2026-18963 est une faille dans le flux de réinitialisation des identifiants de keycloak-services (keycloak#51833). Un attaquant non authentifié peut mener à bien le processus de réinitialisation de mot de passe pour n'importe quel utilisateur sans cliquer sur le lien de vérification par e-mail, puis définir un nouveau mot de passe sur le compte. Aucune interaction de l'utilisateur n'est requise.
Vérifié sur Keycloak 26.7.1 sur une instance jetable. Nous ne publions pas les étapes de reproduction ; les détails ci-dessous sont ceux dont vous avez besoin pour lire les requêtes.
Le flux suit l'écran d'authentification sur lequel il se trouve d'une manière qui n'est pas liée à l'étape qui l'a défini. Cela permet de réintégrer le flux de réinitialisation des identifiants à l'étape de vérification par e-mail, où la méthode vulnérable ResetCredentialEmail.action() renvoie un succès sans jamais vérifier la présence d'un jeton d'action. L'exécution se poursuit ensuite vers le formulaire de mise à jour du mot de passe.
Deux conséquences façonnent chaque requête de ce dépôt :
SEND_RESET_PASSWORD ordinaire. L'absence de cet événement n'est pas une signature.action() marque l'adresse e-mail du compte comme vérifiée avant de renvoyer. Le chemin légitime n'atteint jamais action(), il s'agit donc d'un changement d'état que seul le contournement produit. La Q3 repose sur ce point.Le correctif (keycloak#51844) lie l'état de l'écran à l'exécution qui l'a défini, et ne permet à action() de réussir que lorsqu'un jeton d'action pour cet utilisateur exact est présent.
Gravité : Critique, CVSS v3.1 9.1 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N), selon Red Hat et NVD. La cause racine est une validation d'état incorrecte dans le flux d'authentification, corrigée dans keycloak#51844.
| Flux | Corrigé dans |
|---|---|
| 26.7.x | 26.7.2 (notes de version) |
| 26.6.x | 26.6.6 |
| 26.4.x (LTS) | 26.4.15 |
| 26.8 | 26.8.0 |
Toutes les versions inférieures à celles-ci dans les flux pris en charge sont vulnérables. Les versions hors support (26.5.x, 26.3 et antérieures) ne reçoivent aucun correctif : considérez-vous comme exposé et mettez à niveau vers un flux corrigé. Red Hat indique que l'ancien RH-SSO 7 n'est pas affecté ; le Red Hat Build of Keycloak 26.4/26.6 est corrigé dans 26.4.15-1 / 26.6.6-1.
La désactivation de la réinitialisation de mot de passe en libre-service supprime le point d'entrée vulnérable : Console d'administration > Paramètres du realm > Connexion > « Mot de passe oublié » désactivé, pour chaque realm. Via l'API d'administration : PUT /admin/realms/{realm} avec {"resetPasswordAllowed": false}.
Cela bloque le point de terminaison login-actions/reset-credentials mais empêche également les utilisateurs légitimes de réinitialiser leur propre mot de passe ; considérez donc cela comme une mesure provisoire jusqu'à la mise à niveau. Notez que Red Hat ne liste aucune atténuation approuvée pour cette CVE ; l'application du correctif est la seule véritable solution.
La première version de ce script signalait une réinitialisation terminée qui n'avait aucun SEND_RESET_PASSWORD peu de temps avant.
C'était faux, et
vilmosnagy l'a signalé
après avoir reproduit la CVE sur sa propre instance et constaté que l'événement apparaissait
malgré tout. La raison est la première conséquence ci-dessus : l'authentificateur de mail s'exécute
normalement, donc la victime reçoit un vrai mail de réinitialisation et Keycloak journalise un
SEND_RESET_PASSWORD ordinaire. La vérification était inversée. Elle aurait effacé tous les
comptes compromis qu'elle examinait. Elle a été supprimée.
Les schémas temporels ont un problème plus petit mais réel. L'approche du
script de chasse de thomasdelorge
corrèle SEND_RESET_PASSWORD avec UPDATE_PASSWORD sur un code_id partagé
et signale un court intervalle. La clé de corrélation est correcte, et l'auteur précise
explicitement que le seuil est heuristique. Nos tests disent la même chose : une réinitialisation contournée
et une réinitialisation légitime effectuée dans le même navigateur produisent des types d'événements identiques,
des clés de détail identiques et le même code_id. Seul le délai diffère,
ce qui laisse le seuil porter tout le verdict. Quiconque n'est pas pressé reste
sous ce seuil. Les utilisateurs réels le déclenchent, car le code_id ne reste identique que lorsque le
lien est ouvert dans le navigateur qui a démarré le flux, ce qui est aussi le cas
où le mail est probablement déjà ouvert.
Nous n'avons trouvé aucun événement, aucun détail d'événement et aucune erreur qui distingue les deux. Il n'existe pas d'événement « étape mail ignorée » à rechercher. Ce qui existe, c'est un effet de bord sur l'état, et c'est ce que Q3 utilise.
cve-2026-18963-keycloak-hunt.sql exécute six requêtes en lecture seule :
| Requête | Ce qu'elle trouve |
|---|---|
| Q0 | Si le realm stocke des événements, leur TTL, et si les détails d'événements sont persistés. Q2 corrèle sur le détail code_id, donc si les détails manquent, Q2 est aveugle et son silence ne signifie rien. |
| Q1 | Chaque définition d'identifiant de mot de passe dans la fenêtre d'exposition (credential.created_date). C'est la prise de contrôle elle-même, et elle survit à l'expiration des événements. |
| Q2 | Chaque mise à jour d'identifiant complétée, corrélée avec le mail de réinitialisation de la même session d'authentification, et classifiée. Voir ci-dessous. |
| Q3 | L'effet de bord déterministe : les utilisateurs qui sont email_verified sans cause légitime. |
| Q4 | Les réinitialisations d'identifiants via l'API d'administration et les écritures d'utilisateurs, pour expliquer les lignes Q1 et Q3 et écarter la voie pilotée par l'admin. |
| Q5 | La chronologie brute des événements de réinitialisation/identifiant, pour lire un cas isolé à la main. |