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.
}
// 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
# 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.

