Jul 29, 2026·7 min read·2 visits
ZITADEL allowed self-managing users to request plaintext verification OTPs in API responses by setting the returnCode parameter to true. Standard users could exploit this logic flaw to verify arbitrary email addresses and phone numbers without possessing actual access to the targeted out-of-band communication channel.
A critical authorization bypass vulnerability was identified in the ZITADEL identity management platform, tracked as CVE-2026-54693 (GHSA-jq8w-8q2f-ffm9). Due to incorrect privilege validation in self-service profile modification endpoints, standard authenticated users could obtain plaintext verification codes during email or phone number updates. This allows attackers to claim and verify arbitrary email addresses or phone numbers without controlling the underlying contact methods.
ZITADEL, an open-source identity and access management platform, contains a logical authorization vulnerability tracked under CVE-2026-54693. The flaw is located within the platform's self-management APIs handling email and phone updates. These endpoints are designed to allow users to update their contact information independently.
During a standard update sequence, the application generates a verification code or one-time password and delivers it out-of-band to confirm ownership of the new destination. The vulnerability allows self-managing users to request that the plaintext verification code be returned directly in the API response. This behavior bypasses the requirement for out-of-band delivery entirely.
Attackers can exploit this design flaw to associate arbitrary email addresses or phone numbers with their accounts. This process does not require access to the target inbox or mobile device. The resulting security bypass undermines trust in email and phone verification states throughout the identity provider, compromising downstream applications.
The vulnerability is classified under CWE-863 (Incorrect Authorization). It represents a failure to restrict administrative-level query parameters from standard users. The impact extends to downstream applications that rely on ZITADEL for federated identity and access decisions.
The root cause of the vulnerability resides in ZITADEL's backend authorization logic implemented in Go within the internal/command/ package. The platform provides a returnCode parameter to support administrative workflows, such as automated provisioning or programmatic migrations. When this parameter is set to true, the server serializes and returns the plaintext verification OTP directly in the JSON response payload.
To check user permissions during profile modifications, the command handlers call the checkPermissionUpdateUser method. This function accepts a boolean parameter called allowSelfManagement. In the vulnerable implementation, this parameter was hardcoded to true across multiple update endpoints, including email, phone, and human profile update paths.
Because the system hardcoded allowSelfManagement to true, the authorization layer did not evaluate whether the caller possessed administrative privileges. The authorization layer only validated that the user was updating their own profile. This logic failed to recognize that requesting the verification code in the response is an administrative action.
Consequently, any authenticated user could issue a self-service profile update request with the returnCode parameter set to true. The system processed the request, generated the verification code, and returned the plaintext OTP to the user. This logical oversight allowed standard users to abuse administrative functions designed solely for backend integrations.
The vulnerable code paths are distributed across three primary self-service command files in the backend: internal/command/user_v2_email.go, internal/command/user_v2_phone.go, and internal/command/user_v2_human.go. The flaw is characterized by the static passing of true to the checkPermissionUpdateUser function.
The architectural flow of the vulnerability can be modeled to illustrate how the request bypasses the out-of-band validation channel.
The official fix resolves this issue by dynamically calculating the value of the allowSelfManagement parameter. The patch sets allowSelfManagement to the negation of returnCode (allowSelfManagement := !returnCode). When a client requests the verification code in the API response, allowSelfManagement becomes false, forcing the server to evaluate the request against administrative permissions.
The following code comparison highlights the specific structural changes introduced in the patch for email updates within internal/command/user_v2_email.go:
// VULNERABLE CODE
if err = c.checkPermissionUpdateUser(ctx, cmd.aggregate.ResourceOwner, userID, true); err != nil {
return nil, err
}
// PATCHED CODE
// The allowSelfManagement variable is now dynamically set to false if returnCode is true.
allowSelfManagement := !returnCode
if err = c.checkPermissionUpdateUser(ctx, cmd.aggregate.ResourceOwner, userID, allowSelfManagement); err != nil {
return nil, err
}This pattern is consistently implemented across all affected command files to ensure uniform authorization checks and robust access control enforcement.
Exploitation of this vulnerability requires the attacker to possess a valid, authenticated account on the target ZITADEL instance. No elevated administrative privileges are needed to initiate the attack sequence. The attacker must have network access to the ZITADEL user management API endpoints.
The attack begins when the user submits an HTTP POST request to update their email or phone number. In this request, the attacker specifies the target email address (for example, victim@company.com) and adds the parameter "returnCode": true. The server processes the update and returns a JSON payload containing the plaintext verification code.
Upon receiving the plaintext verification code in the HTTP response, the attacker extracts the code. The attacker then sends a subsequent verification request to the ZITADEL API using the extracted code. Because the code is valid, the server marks the email address or phone number as verified on the attacker's account.
The attack succeeds without generating any out-of-band delivery notifications to the actual owner of the email address or phone number. The attacker completes the validation sequence entirely within the in-band HTTP channel. This allows the attacker to verify arbitrary identities without ownership verification.
The security impact of this vulnerability is critical for environments that rely on email or phone verification for security boundaries. Attackers can claim and verify arbitrary email domains or phone numbers on their accounts. This verified status can bypass security controls or downstream application policies.
In single sign-on (SSO) environments, downstream applications often trust the verification claim provided by ZITADEL. An attacker who verifies an email address belonging to a target domain can log in to connected applications as a member of that domain. This leads to unauthorized data access, privilege escalation, and domain hijacking.
The vulnerability also compromises multi-factor authentication (MFA) and account recovery mechanisms. An attacker can associate and verify their phone number on a victim's profile if they have temporary session access. This modification allows the attacker to establish persistence and bypass subsequent MFA challenges.
The CVSS v4.0 score is calculated as 8.2 (High). The primary drivers of this score are the high impact on integrity and subsequent systems. While confidentiality of ZITADEL itself is not directly compromised, the integrity of the identity claims is completely undermined.
The primary remediation strategy is to upgrade ZITADEL deployments to the official patched releases. For deployments on the v3 branch, administrators must upgrade to version v3.4.11 or higher. For deployments on the v4 branch, administrators must upgrade to version v4.15.1 or higher.
If immediate patching is not possible, organizations should implement monitoring to detect exploit attempts. Administrators should monitor HTTP API logs for requests targeting /v2/users/.../email or /v2/users/.../phone that contain the parameter returnCode: true or ReturnCode: true. Any such request initiated by a non-administrative user indicates active exploitation.
Security teams can also audit the ZITADEL event store for indicators of compromise. Specifically, look for instances where a user.HumanEmailChangedEvent is immediately followed by a user.HumanEmailVerifiedEvent within a very short timeframe. This pattern suggests automated verification bypassing the typical out-of-band latency.
Long-term architectural security requires evaluating how downstream systems trust ZITADEL identity claims. Organizations should implement strict validation of federated claims and avoid relying solely on the email verification flag for sensitive authorization decisions. Applying the principle of least privilege to API client permissions will further limit the attack surface.
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:N/VI:H/VA:N/SC:N/SI:H/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
ZITADEL ZITADEL | >= 2.43.0, < 2.71.19 | 2.71.19 |
ZITADEL ZITADEL | >= 3.0.0-rc.1, < 3.4.11 | 3.4.11 |
ZITADEL ZITADEL | >= 4.0.0-rc.1, < 4.15.1 | 4.15.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-863 |
| Attack Vector | Network |
| CVSS Score | 8.2 (High) |
| Exploit Status | PoC |
| CISA KEV Status | Not Listed |
The software does not perform or incorrectly performs an authorization check when an actor attempts to access a resource or perform an action.
A sensitive data exposure vulnerability (CWE-532) exists in OpenTelemetry Java Instrumentation prior to version 2.28.0. The JDBC auto-instrumentation component's SQL statement sanitizer contains lexer flaws that prevent the correct redaction of administrative passwords under specific conditions, such as when double-quotes represent identifiers or during multi-statement executions separated by semicolons.
CVE-2026-54705 is a critical DOM-based Cross-Site Scripting (XSS) vulnerability affecting the MathLive library prior to version 0.110.0. The flaw stems from a lack of proper character escaping in the rendering path for LaTeX text-mode commands such as \text{} and \mbox{}, enabling unauthenticated attackers to execute arbitrary JavaScript in the victim's browser.
CVE-2026-54735 is a critical Server-Side Request Forgery (SSRF) vulnerability in Prebid Server's bidder adapters, allowing unauthenticated remote attackers to route HTTP requests to arbitrary locations, including internal local host loopbacks and cloud provider metadata endpoints.
CVE-2026-54666 identifies a high-severity code injection vulnerability in the swagger-typescript-api code generator library. The library fails to sanitize route paths parsed from OpenAPI Specification (OAS) documents before interpolating them into generated TypeScript and JavaScript client code. When a developer processes a compromised or malicious OpenAPI specification file, the library writes unescaped string literals and dynamic execution blocks directly into backtick template literals. When the generated client's corresponding API method is executed, the embedded JavaScript executes dynamically with the privileges of the active process.
A type confusion vulnerability exists in the optimizing JIT compilation pipeline of Mozilla SpiderMonkey (Firefox) prior to version 151.0.3. An error in the JIT compiler's Range Analysis optimization pass allows the unsafe elimination of critical type guards. Under specific execution flows, an unauthenticated remote attacker can trigger a mismatch between predicted compile-time types and actual runtime types, resulting in memory corruption and arbitrary code execution within the browser's sandbox environment.
CVE-2026-54690 (GHSA-954p-556p-r752) is a Server-Side Request Forgery (SSRF) vulnerability in the datamodel-code-generator Python library from version 0.9.1 to 0.61.0. The library silently resolves remote JSON Schema references ($ref) over HTTP/HTTPS without verifying the target hosts or IP addresses. Because it automatically follows redirects and permits requests to local and private networks by default, an attacker can submit a crafted schema to trigger connections to internal subnets, localhost, or cloud metadata endpoints. Retrieved sensitive data is subsequently parsed and reflected in the generated Python model files, resulting in local and private data disclosure.