Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2025-31124

CVE-2025-31124: Zitadel Username Disclosure Vulnerability

CVE-2025-31124 is an information disclosure vulnerability in Zitadel that exposes usernames through normalization despite enabled protection. This post covers the technical details, affected versions, and mitigation strategies.

Published:

CVE-2025-31124 Overview

CVE-2025-31124 is an information disclosure vulnerability in Zitadel, an open-source identity infrastructure platform. The flaw allows unauthenticated attackers to enumerate valid usernames despite the administrator enabling the Ignoring unknown usernames protection. While the login flow correctly displays the standard Username or Password invalid prompt, Zitadel normalized the submitted username server-side. This normalization behavior revealed whether the account existed, defeating the anti-enumeration control [CWE-200]. The issue affects multiple release branches and was fixed in versions 2.71.6, 2.70.8, 2.69.9, 2.68.9, 2.67.13, 2.66.16, 2.65.7, 2.64.6, and 2.63.9.

Critical Impact

Remote attackers can confirm the existence of valid user accounts in Zitadel deployments, enabling targeted credential stuffing, phishing, and follow-on account takeover attempts.

Affected Products

  • Zitadel versions prior to 2.63.9 on the 2.63.x branch
  • Zitadel versions prior to 2.64.6, 2.65.7, 2.66.16, 2.67.13, 2.68.9, 2.69.9, and 2.70.8
  • Zitadel versions prior to 2.71.6 on the 2.71.x branch

Discovery Timeline

  • 2025-03-31 - CVE-2025-31124 published to NVD
  • 2026-06-17 - Last updated in NVD database

Technical Details for CVE-2025-31124

Vulnerability Analysis

Zitadel provides an administrator setting called Ignoring unknown usernames. When enabled, Zitadel is expected to display the password prompt and return a generic Username or Password invalid response regardless of whether the submitted username exists. This behavior prevents attackers from distinguishing valid accounts from invalid ones during the login flow.

The login flow honored the setting when generating the user-facing error message. However, an internal normalization step transformed the submitted loginName into a canonical preferredLoginName associated with the resolved user. The response returned this normalized value even when the account was configured to remain hidden. Attackers could compare the value they submitted with the value reflected back to determine whether the account existed.

The vulnerability is classified under [CWE-200] Exposure of Sensitive Information to an Unauthorized Actor. It requires no authentication or user interaction and can be exploited remotely over the network.

Root Cause

The root cause resides in internal/auth/repository/eventsourcing/eventstore/auth_request.go. When an active human user was matched, the request object was populated with user.PreferredLoginName rather than the input the requester supplied. This substitution disclosed the canonical username even when the administrator explicitly configured Zitadel to conceal user existence.

Attack Vector

An unauthenticated attacker submits candidate usernames to the Zitadel login endpoint and observes the resulting response. If the returned loginName differs from the submitted value, the account exists and its canonical form is disclosed. If the values match, the account is not present. This oracle enables large-scale enumeration against Zitadel tenants.

go
 	}
 	// if there's an active (human) user, let's use it
 	if user != nil && !user.HumanView.IsZero() && domain.UserState(user.State).IsEnabled() {
-		request.SetUserInfo(user.ID, loginNameInput, user.PreferredLoginName, "", "", user.ResourceOwner)
+		request.SetUserInfo(user.ID, loginNameInput, preferredLoginName, "", "", user.ResourceOwner)
 		return nil
 	}
 	// the user was either not found or not active

Source: Zitadel security patch commit 14de8ec. The patch replaces the disclosed user.PreferredLoginName with a controlled preferredLoginName value so the server no longer echoes the canonical username back to unauthenticated requesters.

Detection Methods for CVE-2025-31124

Indicators of Compromise

  • High volumes of failed login attempts from a single source or distributed sources targeting the Zitadel login endpoint
  • Sequential or dictionary-style username submissions against /ui/login or the authentication API
  • Login responses returning normalized loginName values that differ from the submitted input

Detection Strategies

  • Compare submitted loginName values against response payloads in Zitadel access logs to identify enumeration attempts
  • Alert on authentication failure spikes exceeding baseline thresholds per source IP, ASN, or user agent
  • Correlate enumeration patterns with subsequent successful logins to detect account takeover progression

Monitoring Recommendations

  • Ingest Zitadel authentication and audit logs into a centralized SIEM for behavioral analysis
  • Monitor the reverse proxy or ingress in front of Zitadel for repeated POST requests to login endpoints
  • Track and alert on password reset or MFA enrollment activity following bursts of failed logins

How to Mitigate CVE-2025-31124

Immediate Actions Required

  • Upgrade Zitadel to the fixed release on your branch: 2.71.6, 2.70.8, 2.69.9, 2.68.9, 2.67.13, 2.66.16, 2.65.7, 2.64.6, or 2.63.9
  • Confirm the Ignoring unknown usernames setting is enabled after upgrading and validate behavior with test accounts
  • Review recent authentication logs for enumeration patterns and force password resets on suspected exposed accounts

Patch Information

The fix is available in the GitHub Security Advisory GHSA-67m4-8g4w-633q and applied in commit 14de8ec. Container images and binaries are published under the corresponding Zitadel GitHub releases.

Workarounds

  • Place rate limiting and IP reputation controls in front of the Zitadel login endpoint to slow enumeration
  • Enforce multi-factor authentication so that disclosed usernames alone cannot lead to account compromise
  • Restrict administrative and self-service login endpoints to trusted networks where operationally feasible
bash
# Verify the running Zitadel version and upgrade to a fixed release
zitadel --version

# Example: pull a patched container image
docker pull ghcr.io/zitadel/zitadel:v2.71.6

# Restart the service after applying the new image or binary
systemctl restart zitadel

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.