| Package Name | Ecosystem | Vulnerable Versions | First Patched Version |
|---|---|---|---|
| github.com/zitadel/zitadel | go | < 0.0.0-20250528081227-c097887bc5f6 | 0.0.0-20250528081227-c097887bc5f6 |
| github.com/zitadel/zitadel/v2 | go | >= 2.38.3, < 2.70.12 | 2.70.12 |
| github.com/zitadel/zitadel/v2 | go | >= 3.0.0-rc1, < 3.2.2 | 3.2.2 |
| github.com/zitadel/zitadel/v2 | go | >= 2.71.0, <= 2.71.10 | 2.71.11 |
| github.com/zitadel/zitadel/v2 | go | < 2.38.2-0.20240919104753-94d1eb767837 |
The vulnerability (CVE-2025-48936) in ZITADEL allowed account takeover via malicious X-Forwarded-Proto or Forwarded header injection. ZITADEL used these headers to construct the URL for password reset confirmation links. An attacker could manipulate these headers to make the generated link point to a malicious domain.
The root cause of the vulnerability lies in two key functions within internal/api/http/middleware/origin_interceptor.go:
hostFromRequest: This function was responsible for parsing headers like Forwarded and X-Forwarded-Proto to extract the protocol. Critically, it did not validate the extracted protocol string (e.g., ensuring it was only 'http' or 'https'). This meant an attacker-controlled, unvalidated protocol string could be passed on for further processing.
composeDomainContext: This function used the (potentially unvalidated) protocol from hostFromRequest to determine the final protocol for the password reset URL. Its logic for deciding this protocol was insufficient. It could be manipulated to use an 'http' scheme when 'https' was appropriate (protocol downgrade) or use an attacker-controlled scheme derived from the manipulated headers. This allowed the construction of a password reset link pointing to an attacker's server, enabling them to capture the password reset token if the user clicked the link.
The patch addresses these issues by:
hostFromRequest to ensure that only 'http' or 'https' are accepted as protocol strings from headers.enforceHttps flag and a helper function protocolFromRequest within composeDomainContext to implement stricter logic for determining the protocol, preventing downgrades and prioritizing secure configurations.During exploitation, these two functions would be involved in processing the malicious headers and constructing the manipulated URL. Therefore, their names would likely appear in runtime profiles or stack traces.