CVE-2026-29067
ZITADEL is an open source identity management platform. From version 4.0.0-rc.1 to 4.7.0, a potential vulnerability exists in ZITADEL's password reset mechanism in login V2. ZITADEL utilizes the Forwarded or X-Forwarded-Host header from incoming requests to construct the URL for the password reset confirmation link. This link, containing a secret code, is then emailed to the user. This issue has been patched in version 4.7.1.
How AI Introduced This
The vulnerable behavior stems from building IDP redirect flows using instance selection derived from request-controlled headers via `getServiceUrlFromHeaders`, while also constructing success/failure URLs from the original/public host. The fix specifically replaces this with `getServiceConfig`, which pins `baseUrl` to `ZITADEL_API_URL` and separates `instanceHost`/`publicHost`, indicating the bug was improper instance validation rather than the new fallback logic itself. This suspected commit introduced the new `redirectUserToIDP` fallback path that uses `serviceUrl` and `organization` to redirect users to an organization-level IDP, thereby adding the vulnerable V2 login takeover/open-redirect-capable flow into `loginname.ts`.
▶Bug-Introducing Commits(1)
chore: consistent naming for organization domain (#11356)
From squash merge 11a35f4ef48c
▶Sub-commits(56)
docs: move to apps folder and copy state from main
chore: rename meta data to metadata (#11322)
chore: renamed passwordless to passkey (#11338)
chore: rename password change to password changed (#11323)
chore: replace given and family names with first and last names (#11343)
chore: naming custom domain (#11383)
chore: naming trusted domain (#11384)
chore: replace "manager role" with "administrator role" (#11395)
chore: management console naming inconsistency (#11390)
docs: introduce versioned docs and migrate to fuma (#11166)
chore: naming inconsistency application (#11431)
chore: renamed one time password to OTP (#11447)
chore: naming inconsistency project grants (#11488)
chore(docs): User (Human) naming consistency (#11512)
chore: rename IAM to instance (#11351)
chore: rename manager/member to administrator (#11542)
docs: fixed some typos, formatting, grammar (#11540)
chore: Service Account Naming Consistency (#11557)
fix: correctly send links to login v2 in email notifications (#10711)
fix: added `login_hint` to the idp intent (#11552)
chore: rename login data to login details (#11127)
fix(benchmark): set proper audience to introspect token (#11586)
feat(login): use OpenSSL CA store for TLS certificate validation (#11562)
chore(agents): add agents files (#11497)
fix(console): generic oidc help button opens Google config page (#11605)
chore: rename authorization to role assignment (#11588)
fix(login): update login logic to correctly handle email and phone re… (#11618)
feat: add current password field to password reset (#11534)
chore: rename configuration to settings (#11568)
chore: consistent naming for organization domain (#11356)
docs: fix readme logo file path (#11628)
feat(api): allow specifying access token type for user of type machine (#11599)
chore: update PR title convention and semantic types in AGENTS.md and CONTRIBUTING.md (#11620)
fix: set refresh token in the `RetrieveIdentityIntentResponse` (#11613)
chore: consistent naming for object ids (#11604)
chore(build): enhance proto caching and install binary plugins for improved performance, remove reliance on BSR (#11634)
feat(login): add autoFocus to input components (#11566)
fix: session termination after user deletion/deactivation (#11644)
fix(login): CSP img-src resolved at build time instead of runtime (#11603)
fix: allow creating new invite code before previous is invalid (#11649)
docs: add description frontmatter to content pages for SEO (#11654)
feat: allow adding trusted domains in instance setup (#11169)
docs: added docs for the new dotnet example (#11541)
feat(login): redirect configuration options in multi-domain setups (#11527)
feat(login): dynamically configure languages based on settings (#11372)
Prevent failure in setup step 69 if `cache.objects` does not exist (#11673)
feat(login): add LOGIN_SERVICE_KEY_FILE authentication support (#11572)
chore: improve docker compose template, tests and docs (#11593)
feat(login): add optional TLS termination support (#11663)
fix(login): check for primary auth methods on user discovery (#11689)
docs: update custom domain guide for customer portal (#11691)
chore: update the readme (#11694)
docs(deps): update fumadocs to latest versions (#11692)
fix(test): resolve nil-pointer panic in TestCommandSide_ChangeUserHuman (#11695)
re-add missing file
fix test
Tribunal Analysis
3 agents▶CONFIRMEDGPT-5.492%
The vulnerable behavior stems from building IDP redirect flows using instance selection derived from request-controlled headers via `getServiceUrlFromHeaders`, while also constructing success/failure URLs from the original/public host. The fix specifically replaces this with `getServiceConfig`, which pins `baseUrl` to `ZITADEL_API_URL` and separates `instanceHost`/`publicHost`, indicating the bug was improper instance validation rather than the new fallback logic itself. This suspected commit introduced the new `redirectUserToIDP` fallback path that uses `serviceUrl` and `organization` to redirect users to an organization-level IDP, thereby adding the vulnerable V2 login takeover/open-redirect-capable flow into `loginname.ts`.
- •In commit 11a35f4..., `redirectUserToIDP(userId?: string, organization?: string)` was added and for org-level fallback it calls `getActiveIdentityProviders({ serviceUrl, orgId: organization })` and `startIdentityProviderFlow({ serviceUrl, idpId: activeIdps[0].id, ... })`.
- •At that commit, `getServiceUrlFromHeaders` derives `serviceUrl` from `x-zitadel-forward-host` or `host`, so instance selection is influenced by inbound headers rather than a validated config.
- •The fix commit replaces `getServiceUrlFromHeaders` with `getServiceConfig`, whose implementation always uses `ZITADEL_API_URL` as `baseUrl` and separately passes sanitized `instanceHost`/`publicHost`, directly addressing improper instance validation.
- •The fix also replaces `getOriginalHost()` with `getPublicHost(_headers)`, showing the security-sensitive distinction between instance routing and public-facing redirect host in this exact code path.
▶UNLIKELYClaude Opus 4.678%
The vulnerability (CVE-2026-29067) is about improper instance validation due to trusting user-controllable headers (`x-zitadel-forward-host`, `x-forwarded-host`) in `getServiceUrlFromHeaders` and `getOriginalHost` to determine the ZITADEL instance and redirect URLs. The BIC (11a35f4ef48c7bbbe0d049a9a655477c59951391) only refactored IDP redirect logic by merging two functions and adding fallback behavior. The vulnerable functions `getServiceUrlFromHeaders` and `getOriginalHost` were already used in the file before this commit (confirmed at parent commit b56bedc77). While the BIC did add new call sites for these vulnerable functions within the refactored code, it did not introduce the core vulnerability — the improper header-based instance resolution that the fix addresses.
- •The vulnerable functions getServiceUrlFromHeaders and getOriginalHost were already imported and used in loginname.ts before the BIC (at commit b56bedc77, lines 12, 25, 38, 81, 82, 131, 132)
- •The BIC only refactored IDP redirect logic by merging redirectUserToSingleIDPIfAvailable and redirectUserToIDP into a single function with fallback behavior
- •The fix commit changes the fundamental approach: replacing getServiceUrlFromHeaders with getServiceConfig (which requires ZITADEL_API_URL) and getOriginalHost with getPublicHost (which separates instance host from public host) - these are architectural changes to functions that predate the BIC
- •The core vulnerability is in service-url.ts and host.ts, not in the IDP redirect logic that the BIC modified
▶UNLIKELYGemini 3.1 Pro95%
The vulnerability (CVE-2026-29067) is an Improper Instance Validation issue in V2 Login, which allows Account Takeover. The fix commit addresses this by centralizing host resolution logic, replacing `getOriginalHost` with `getPublicHost` and `getServiceUrlFromHeaders` with `getServiceConfig` to prevent attackers from manipulating headers like `Host` or `X-Forwarded-Host`. The suspected Bug-Introducing Commit (11a35f4ef48c7bbbe0d049a9a655477c59951391) refactors the IDP redirection logic in `loginname.ts`. However, the diff clearly shows that the vulnerable functions `getOriginalHost` and `getServiceUrlFromHeaders` were already being used in this file prior to this commit. The suspected BIC merely moved the existing vulnerable code around and did not introduce the improper host validation logic itself. Therefore, it is unlikely that this commit introduced the vulnerability.
- •The fix commit (4c879b47334e01d4fcab921ac1b44eda39acdb96) addresses the vulnerability by replacing `getOriginalHost` with `getPublicHost` and `getServiceUrlFromHeaders` with `getServiceConfig` to properly validate and separate instance and public hosts.
- •The suspected BIC (11a35f4ef48c7bbbe0d049a9a655477c59951391) refactors IDP redirection logic in `apps/login/src/lib/server/loginname.ts`.
- •The diff of the suspected BIC shows that `getOriginalHost` and `getServiceUrlFromHeaders` were already being used in `redirectUserToSingleIDPIfAvailable` and `redirectUserToIDP` before the commit.
- •Since the vulnerable host resolution functions were already present and used in the login flow prior to the suspected BIC, this commit did not introduce the vulnerability.
Insufficient validation of host/instance headers or parameters when initiating authentication flows, leading to potential redirection or session hijacking across instances.▶AI Signals(1)
| GitHub Copilot | Squash PR co-author (generic) | Co-authored-by: Copilot <175728472+Copilot | 1% |