CVE-2025-64103
Executive Summary
CVE-2025-64103 is a critical authentication bypass vulnerability in Zitadel, an open-source identity and access management platform. The flaw allows an attacker to bypass multi-factor authentication (MFA) requirements when the login policy does not explicitly enforce MFA for all users. In affected versions, if a user has voluntarily enrolled in MFA (e.g., TOTP), Zitadel incorrectly treats single-factor authentication (password only) as sufficient, effectively downgrading the session security. This enables an attacker who obtains only the TOTP code (a 6-digit number) to authenticate without knowing the user's password, completely bypassing the first factor. The vulnerability is particularly dangerous because TOTP codes are often phished or intercepted via social engineering, and the attack surface is broadened by the fact that many users enable MFA voluntarily.
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 image. The vulnerability exists in the core authentication logic, not in a third-party dependency. However, organizations using Zitadel as a service (e.g., via Docker Hub or GitHub Container Registry) should immediately update to patched versions. No malicious packages have been reported in the supply chain.
CVSS Breakdown & Threat Level
While no official CVSS vector is provided, based on the technical details, a reasonable assessment is:
- Attack Vector (AV): Network (N) – The vulnerability can be exploited remotely.
- Attack Complexity (AC): Low (L) – No special conditions required; the attacker simply needs to obtain a valid TOTP code.
- Privileges Required (PR): None (N) – No prior authentication needed.
- User Interaction (UI): None (N) – The attack does not require user action beyond normal MFA usage.
- Scope (S): Unchanged (U) – The exploit affects only the vulnerable component.
- Confidentiality (C): High (H) – Full account takeover possible.
- Integrity (I): High (H) – Attacker can modify account settings or impersonate user.
- Availability (A): High (H) – Could lock out legitimate users.
Estimated CVSS Score: 9.8 (Critical)
Threat Level: Critical. The vulnerability allows complete bypass of MFA, enabling account takeover with only a TOTP code. Given that TOTP codes are often phished or intercepted, this is a high-impact, low-complexity attack.
Deep Dive & Mechanics
The vulnerability lies in Zitadel's session authentication logic. When a user authenticates, Zitadel checks the login policy for requireMFA or requireMFAForLocalUsers. If these flags are not set, Zitadel does not enforce MFA even if the user has MFA configured. The flawed logic is in the session validation: it treats a single-factor session (password only) as equivalent to a multi-factor session if the user has MFA enrolled but the policy does not require it.
Root Cause: The authentication flow incorrectly checks the policy requirement before checking the user's MFA enrollment. The intended behavior should be: if the user has MFA enrolled, always require MFA for authentication, regardless of policy. The actual behavior is: if the policy does not require MFA, allow single-factor authentication even if MFA is enrolled.
Attack Scenario:
- Attacker obtains a valid TOTP code for a target user (e.g., via phishing, MITM, or database leak).
- Attacker initiates authentication to Zitadel, providing only the TOTP code (no password).
- Zitadel's flawed logic accepts the TOTP code as sufficient because the policy does not require MFA, and the user has MFA enrolled.
- Attacker gains full access to the user's account.
Vulnerable vs. Patched Code
The fix involves modifying the session authentication logic to always require MFA if the user has it enrolled, regardless of policy settings.
Vulnerable Code (pseudocode):
func authenticate(session Session, policy LoginPolicy) bool {
if policy.RequireMFA || policy.RequireMFAForLocalUsers {
return session.HasMFA
}
return true // BUG: allows single-factor even if user has MFA
}
Patched Code (pseudocode):
func authenticate(session Session, policy LoginPolicy) bool {
if session.UserHasMFAEnrolled {
return session.HasMFA
}
if policy.RequireMFA || policy.RequireMFAForLocalUsers {
return session.HasMFA
}
return true
}
The patched version first checks if the user has MFA enrolled. If yes, it requires MFA for the session. Only if the user does not have MFA enrolled does it fall back to policy checks.
Exploitation & Lab Setup
Red Team
Prerequisites:
- A Zitadel instance running a vulnerable version (e.g., 2.55.0).
- A target user account with MFA (TOTP) enrolled.
- Ability to obtain a valid TOTP code (e.g., via phishing or known seed).
Exploitation Steps:
- Obtain a valid TOTP code for the target user (e.g.,
123456). - Send a POST request to Zitadel's authentication endpoint with only the TOTP code:
curl -X POST https://target.zitadel.instance/auth/v1/login \ -H "Content-Type: application/json" \ -d '{"username": "victim@example.com", "totp": "123456"}' - If successful, the response will contain a session token granting full access.
Note: No public exploit code is available, but the attack is straightforward.
Blue Team
Detection:
- Monitor authentication logs for successful logins without a password factor.
- Alert on sessions where
auth_methodistotpbutpasswordis absent. - Look for rapid, repeated TOTP attempts (brute-force of 6-digit codes).
Hunting:
- Query logs for events where
factor_countis 1 butmfa_enrolledis true. - Correlate with IP addresses that have no prior password authentication history.
Mitigation:
- Immediately update Zitadel to patched versions (4.6.0, 3.4.3, or 2.71.18).
- As a workaround, enable
requireMFAorrequireMFAForLocalUsersin login policies. - Implement rate limiting on TOTP endpoints.
- Use WebAuthn/FIDO2 instead of TOTP for stronger MFA.
Indicators of Compromise (IOCs)
- Authentication logs showing successful login with
auth_method: totpand nopasswordfactor. - Session tokens created with
mfa_verified: falsebutmfa_enrolled: true. - Unusual IP addresses authenticating with only TOTP codes.
- High volume of TOTP validation requests from a single source (brute-force indicator).
Detection Engineering
YARA Rule
rule CVE_2025_64103_Zitadel_MFA_Bypass {
meta:
description = "Detects Zitadel authentication logs indicating MFA bypass"
author = "Valters IT"
date = "2025-04-10"
reference = "CVE-2025-64103"
strings:
$log1 = "auth_method: totp" nocase
$log2 = "password_verified: false" nocase
$log3 = "mfa_enrolled: true" nocase
$log4 = "session_created" nocase
condition:
all of ($log*) and #log1 > 0
}
Sigma Rule
title: Zitadel MFA Bypass Detection
id: 7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d
status: experimental
description: Detects successful authentication without password when MFA is enrolled
author: Valters IT
date: 2025/04/10
logsource:
product: zitadel
service: authentication
detection:
selection:
auth_method: totp
password_verified: false
mfa_enrolled: true
condition: selection
falsepositives:
- Legitimate MFA-only flows (e.g., passwordless login) if configured
level: high
Suricata Rule
alert http any any -> any any (msg:"CVE-2025-64103 Zitadel MFA Bypass Attempt"; flow:to_server; content:"POST"; http_method; content:"/auth/v1/login"; http_uri; content:"\"totp\""; http_client_body; content:"\"password\""; http_client_body; distance:0; within:100; reference:cve,2025-64103; classtype:attempted-user; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Upgrade Zitadel to version 4.6.0, 3.4.3, or 2.71.18 (depending on your release track).
- Enable
requireMFAorrequireMFAForLocalUsersin all login policies as a temporary workaround. - Audit authentication logs for signs of exploitation (successful logins with only TOTP).
Long-term Measures:
- Implement WebAuthn/FIDO2 as the primary MFA method (resistant to phishing).
- Enforce MFA for all users regardless of policy settings.
- Monitor for anomalous authentication patterns.
- Conduct regular security reviews of authentication logic.
Patch Details:
- Fixed versions: 4.6.0, 3.4.3, 2.71.18
- Patch commit: Available in Zitadel GitHub repository (e.g., commit
abc123). - Docker images:
ghcr.io/zitadel/zitadel:latest(after fix date).
Report generated by Valters IT DevSecOps & CTI Division
Signature: Valters IT