ZITADEL Password Reset Flow Exploitable via Forged Host Headers
ZITADEL, a widely deployed open-source identity management platform, has patched CVE-2026-29067, a high-severity host header injection vulnerability in its login V2 password reset mechanism. The flaw allows an unauthenticated attacker to poison password reset emails, redirecting secret reset codes to an attacker-controlled domain and achieving full account takeover without ever knowing the target's current credentials.
The vulnerability carries a CVSS score of 8.1 and affects ZITADEL versions 4.0.0-rc.1 through 4.7.0. A patch is available in version 4.12.0.
Vulnerability Details
| Attribute | Value |
|---|---|
| CVE ID | CVE-2026-29067 |
| CVSS Score | 8.1 (High) |
| Affected Versions | ZITADEL 4.0.0-rc.1 – 4.7.0 |
| Patched Version | ZITADEL 4.12.0 |
| CWE | CWE-640: Weak Password Recovery Mechanism |
| Attack Type | Host/Forwarded Header Injection → Password Reset Poisoning |
| Authentication Required | None |
| User Interaction | Required (victim clicks poisoned reset link) |
| Disclosure Date | March 7, 2026 |
How the Attack Works
The Root Cause
ZITADEL's login V2 password reset function constructs the URL embedded in reset emails by reading the Forwarded or X-Forwarded-Host HTTP headers from the incoming request. These headers are intended to communicate the original client-facing hostname when ZITADEL sits behind a reverse proxy.
However, if these headers are not stripped or validated by an upstream proxy, an attacker can inject an arbitrary hostname into the request. ZITADEL will then embed that attacker-controlled domain into the password reset confirmation URL — and send it to the victim's email address.
Attack Chain
1. Attacker identifies a valid user email address in the target ZITADEL deployment
2. Attacker sends a password reset request to the ZITADEL API
— includes a forged "X-Forwarded-Host: attacker.example.com" header
3. ZITADEL constructs the reset URL using the forged hostname:
https://attacker.example.com/ui/login/password/reset?code=SECRET_TOKEN
4. ZITADEL emails the victim the poisoned reset link
5. Victim clicks the link — browser navigates to attacker.example.com
6. Attacker's server captures the SECRET_TOKEN from the URL
7. Attacker uses the SECRET_TOKEN to reset the victim's password
8. Attacker logs in as the victim — full account takeover achievedWhy This Is Dangerous
The attack is entirely server-side — the attacker never needs to be on the victim's network, intercept traffic, or exploit a client-side vulnerability. It requires only:
- Knowledge of a valid user email address (often obtainable via OSINT or user enumeration)
- The ability to send an HTTP request with a forged header (trivially achievable)
- The victim to click a link in an email (standard user behavior for password resets)
If the target account is protected by MFA or Passwordless authentication, the attacker will still capture the reset token but may not be able to complete a login without the second factor — making MFA an effective mitigating control even though it does not prevent the token capture itself.
Affected Deployments
| Scenario | Risk Level |
|---|---|
| Self-hosted ZITADEL without a hardening proxy | Critical — headers reach ZITADEL unfiltered |
| Self-hosted with proxy that strips Forwarded headers | Mitigated |
| Cloud-hosted ZITADEL (vendor-managed) | Lower — vendor controls proxy configuration |
| Deployments on 4.0.0-rc.1 to 4.7.0 | Vulnerable — upgrade required |
| Deployments on 4.12.0+ | Patched |
Remediation
Option 1: Upgrade to ZITADEL 4.12.0 (Recommended)
ZITADEL 4.12.0 adds validation of the Forwarded and X-Forwarded-Host headers against a configured allowlist of trusted hostnames, preventing injection of arbitrary values.
# Pull patched Docker image
docker pull ghcr.io/zitadel/zitadel:v4.12.0
# Kubernetes Helm upgrade
helm upgrade zitadel zitadel/zitadel --set image.tag=v4.12.0Option 2: Strip Forwarded Headers at the Proxy Layer
Configure your reverse proxy (Nginx, Caddy, Traefik, HAProxy) to delete or override the Forwarded and X-Forwarded-Host headers before forwarding requests to ZITADEL:
# Nginx — strip and re-set forwarded headers
proxy_set_header Forwarded "";
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto $scheme;# Traefik middleware — strip headers
http:
middlewares:
strip-forwarded:
headers:
customRequestHeaders:
Forwarded: ""
X-Forwarded-Host: ""Option 3: Enforce MFA Across All Accounts
While MFA does not prevent the reset token from being captured, it blocks the attacker from completing authentication after resetting the password. Enforce MFA organization-wide as a layered defense.
Detection
Review ZITADEL access logs or upstream proxy logs for password reset requests that include suspicious X-Forwarded-Host values:
# Check for password reset requests with non-standard host headers
grep "POST.*password.*reset\|POST.*ui/login/password" /var/log/nginx/access.log | \
grep -v "yourdomain.com"
# ZITADEL application logs — look for reset requests
journalctl -u zitadel | grep -i "password reset" | grep -v "yourdomain.com"Related ZITADEL Vulnerabilities (March 2026)
Three other ZITADEL vulnerabilities were disclosed on the same date:
| CVE | CVSS | Description |
|---|---|---|
| CVE-2026-29191 | 9.3 Critical | XSS in /saml-post — 1-click account takeover |
| CVE-2026-29067 | 8.1 High | Password reset host header injection |
| CVE-2026-29192 | 7.7 High | Stored XSS via Default URI Redirect |
| CVE-2026-29193 | TBD | Login V2 policy bypass — unauthorized self-registration |
All are resolved in ZITADEL version 4.12.0.