Sep 14, 2026·7 min read·22 visits
ZITADEL prior to v4.15.3 fails to validate that a subject token belongs to the requesting client or client project, and fails to ensure requested scopes are a subset of the original token scopes. This allows attackers to escalate privileges or bypass cross-client audience boundaries.
A security vulnerability in ZITADEL's backend implementation of the OAuth2 Token Exchange endpoint allows authenticated clients to perform scope escalation and cross-client audience bypass. Prior to version 4.15.3, the Token Exchange flow lacked crucial validation logic, enabling low-privilege tokens to be exchanged for high-privilege tokens or tokens valid within other client applications, violating the OAuth2 delegation model.
The OAuth2 Token Exchange protocol, defined in RFC 8693, allows a client application to exchange an existing security token for a new security token. This mechanism supports patterns such as impersonation, delegation, and token transitions within multi-tier architectures. In ZITADEL's architecture, the OpenID Connect (OIDC) backend handles these requests at the /oauth/v2/token endpoint when the grant type is set to urn:ietf:params:oauth:grant-type:token-exchange.
Prior to version 4.15.3, ZITADEL's backend implementation of the token exchange flow failed to perform two critical authorization boundaries. First, the server allowed clients to submit access tokens belonging to entirely different client applications or projects as the subject_token without validating ownership or target audience. Second, the server did not verify that the scopes requested in the exchange request were a subset of the scopes already granted in the source token.
This lack of validation permits a low-privilege token to serve as a stepping stone to acquire a high-privilege token, resulting in vertical privilege escalation. Additionally, because the client can use a token issued for a completely different client context, the security model suffers from a horizontal cross-client audience bypass. Organizations relying on ZITADEL to segregate permissions across disparate applications are particularly exposed to unauthorized data access and integrity violations.
The root cause of CVE-2026-56668 lies within the file internal/api/oidc/token_exchange.go in ZITADEL's core identity provider service. The verification logic is divided into two distinct failure points that collectively compromise the OAuth2 token delegation structure. The first failure point is located in the verifyExchangeToken function, which handles the validation of incoming subject_token and actor_token payloads.
When a standard access token (non-Personal Access Token) is provided, the backend validates the cryptographic signature and token expiration but does not verify whether the audience of the token aligns with the client application requesting the exchange. Specifically, the code omitted a call to match the token's audience list against the requesting client's ID or the project ID to which the client belongs. This allowed an authorized client to reuse an access token minted for another application to perform token exchange operations in its own domain.
The second failure point resides within the validateTokenExchangeScopes helper function. This function was designed to determine the final set of scopes assigned to the newly exchanged token. In a secure implementation, the requested scopes must be a mathematical subset of the scopes present in the original subject token. However, ZITADEL's implementation only defaulted to the subject's scopes if the requester left the requestedScopes list empty. When explicit scopes were requested, the server validated that the client was allowed to request those scopes generally, but completely bypassed checking whether they were authorized on the specific subject token being exchanged.
The vulnerability is resolved by modifying both validation vectors in internal/api/oidc/token_exchange.go. The following code block illustrates the patch applied to introduce target audience validation during token exchange processing:
// Prior to patch: standard access tokens bypassed audience matching
// Patched implementation:
if !token.isPAT {
if err = validateIntrospectionAudience(token.audience, client.GetID(), client.client.ProjectID); err != nil {
return nil, zerrors.ThrowPermissionDenied(err, "OIDC-zi9Y0", "Errors.TokenExchange.Token.Invalid")
}
}This ensures that the requesting client cannot supply a token meant for a different context. The second modification addresses the scope verification logic in validateTokenExchangeScopes. The comparison checks were refactored to enforce strict subset constraints:
// Patched scope validation loop
for _, scope := range requestedScopes {
if !slices.Contains(subjectScopes, scope) || !slices.Contains(actorScopes, scope) {
return nil, oidc.ErrInvalidScope().WithDescription("scope %q not found in subject or actor token", scope)
}
}The loop iterates through each element of requestedScopes. It utilizes Go's slices.Contains utility to assert that every requested scope is strictly bounded by both the subject token scopes and actor token scopes if present. Any deviation terminates the request immediately with an invalid scope error.
To exploit this vulnerability, an attacker requires valid client credentials or a low-privilege authenticated token to establish a base of operations on the vulnerable ZITADEL server. The attack is divided into two phases: token acquisition and token exchange exploitation. First, the attacker obtains an access token with minimal scopes, such as openid, from a target client application.
The attacker then constructs an HTTP POST request targeting the ZITADEL token endpoint. In this request, the attacker specifies the grant type as urn:ietf:params:oauth:grant-type:token-exchange and submits the low-privilege access token as the subject_token. In the scope parameter, the attacker includes highly privileged scopes, such as offline_access or backend administration scopes, which were not associated with the original token.
Upon receiving the request, the vulnerable server fails to confirm that the requested scopes are a subset of the subject token scopes. The server processes the request and issues a new access token containing the escalated scopes. The attacker can then utilize this newly minted token to access restricted administrative resources, completely bypassing the OAuth2 delegation boundary.
The impact of CVE-2026-56668 is classified as High, with a CVSS v3.1 base score of 8.1. The primary consequences of successful exploitation are privilege escalation and cross-client authorization bypass. Since ZITADEL acts as the centralized identity provider for organizations, a compromise of the authorization logic in its token endpoint directly undermines the security posture of all downstream applications relying on it.
An attacker who successfully exploits this vulnerability can escalate standard user permissions to administrative level permissions within any resource server that relies on ZITADEL-issued tokens. Furthermore, the cross-client audience bypass allows malicious or compromised client applications to hijack sessions and impersonate users across different application projects, violating multi-tenant isolation assumptions.
Despite the severity of this issue, the exploit complexity is Low, and the attack vector is Network, meaning it can be executed remotely without local system access or user interaction. There is currently no evidence of active exploitation in the wild, and the vulnerability is not listed in the CISA Known Exploited Vulnerabilities catalog. However, the availability of clear proof-of-concept tests within the public repository increases the likelihood of opportunistic exploitation against unpatched deployments.
The official patch introduced in version 4.15.3 completely resolves the identified logical gaps. By incorporating validateIntrospectionAudience and enforcing a strict loop checking of scopes, ZITADEL has addressed both the audience bypass and the scope escalation attack paths. The regression tests added to the integration suite ensure that future updates will not reintroduce these logical omissions.
Organizations running ZITADEL versions older than 4.15.3 must upgrade their deployments to the latest patched version immediately. In scenarios where immediate patching is unfeasible, administrators should consider disabling the Token Exchange grant type for clients that do not strictly require it, thereby limiting the exposed attack surface.
Additionally, security teams should implement detection mechanisms. This includes monitoring authorization logs for token exchange requests that result in errors such as OIDC-zi9Y0 or invalid_scope, as these can indicate exploitation attempts. Network-level WAF rules can also be constructed to inspect payload parameters on /oauth/v2/token for token exchange requests and cross-reference them with threat intelligence indicators.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
ZITADEL ZITADEL | < 4.15.3 | 4.15.3 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-862 |
| Attack Vector | Network |
| CVSS Score | 8.1 |
| EPSS Score | 0.00413 (Percentile: 34.75%) |
| Impact | Privilege Escalation & Audience Bypass |
| Exploit Status | Proof of Concept available in tests |
| KEV Status | Not listed |
The software does not perform an authorization check when an actor attempts to access a resource or perform an action.
CVE-2026-115908 (GHSA-hjqx-j4rw-g7xv) is a high-severity path traversal and link-following vulnerability in the Rust zip library (zip-rs/zip2) affecting versions >= 7.2.0 and < 9.0.0. Because ZipArchive::extract and ZipArchive::extract_unwrapped_root_dir validate symbolic link targets solely via lexical prefix comparisons rather than resolving intermediate filesystem links, an attacker who knows or can guess the absolute extraction path can construct multi-hop symlink chains that escape the destination directory, enabling arbitrary file creation and overwrite with the privileges of the extracting process.
CVE-2026-115907 is an uncontrolled resource consumption vulnerability in the Rust zip crate (versions 5.1.0 through 8.6.0, and 9.0.0 pre-releases) when compiled with the optional legacy-zip feature flag. The vulnerability resides in the legacy decompression decoders—Shrink, Reduce, and Implode—which directly pass an archive-declared 64-bit uncompressed size from a ZIP64 extended information extra field to Vec::reserve() before validating the compressed data stream. By supplying a malformed ZIP archive with a declared uncompressed size exceeding isize::MAX (such as u64::MAX), an unauthenticated attacker can trigger an unhandled capacity overflow panic in the Rust standard library allocator, terminating the calling thread or aborting the entire process.
Twisted versions up to and including 26.4.0 are vulnerable to an unauthenticated remote denial-of-service attack via the HTTP/2 Rapid Reset technique (a variant of CVE-2023-44487). The HTTP/2 connection handler in twisted.web processes pipelined HEADERS and RST_STREAM frames sequentially within the same TCP segment. Because the request dispatch and synchronous rendering occur upon receiving the StreamEnded event before the subsequent StreamReset event is evaluated, an attacker can force the server to expend CPU cycles rendering responses while immediately evicting stream state to bypass concurrent stream limits.
An inefficient algorithmic complexity vulnerability exists in the npm package decode-uri-component prior to version 0.5.1. When processing malformed URI strings containing invalid percent-escape sequences, the library falls back to a custom decoder that collects distinct percent-encoded runs into a dictionary and executes a full-string regular expression replacement for each entry. Supplying a payload with thousands of distinct percent-encoded sequences alongside a malformed escape triggers quadratic O(K * L) execution time, starving the single-threaded Node.js event loop and resulting in an unauthenticated Denial of Service.
Open Neural Network Exchange (ONNX) versions 1.4.0 prior to 1.22.0 contain a null pointer dereference (CWE-476) and a signed-to-unsigned integer conversion error (CWE-195) in the shape inference functions for the Scan operator. When processing an untrusted ONNX model, the functions ScanInferenceFunction, ScanInferenceFunction_opset8, and ScanInferenceFunction_opset9 fail to validate the presence and value of the required num_scan_inputs attribute. Omitting the attribute results in a direct null pointer dereference that crashes the host process via SIGSEGV, while supplying a negative value triggers an integer wrap-around during type narrowing that leads to an unhandled allocation failure. Notably, models containing a negative num_scan_inputs value bypass standard validation via onnx.checker.check_model().
CVE-2026-91403 is a critical cryptographic trust validation flaw (CWE-327) in the Java Secure Socket Extension (JSSE) component of Oracle Java SE, Oracle GraalVM, and OpenJDK builds. Triggered by the compromise of private signing keys for eight intermediate Certificate Authorities operated by eMudhra (emSign), unpatched Java runtime environments implicitly trust fraudulent TLS and code-signing certificates issued by these compromised intermediates. Because Java disables online certificate revocation checking (OCSP/CRL) by default, an unauthenticated network attacker in an Adversary-in-the-Middle (AiTM) position can intercept, decrypt, and modify encrypted TLS communications or bypass code signature verification without triggering security exceptions.