CVE-2026-56664 Overview
CVE-2026-56664 is a session freshness validation flaw in ZITADEL, an open source identity management platform. The vulnerability resides in the external JSON Web Token (JWT) Identity Provider (IdP) validation logic in internal/idp/providers/jwt/session.go. When an incoming JWT omits the iat (issued at) claim, ZITADEL skips the maximum token age check entirely. This allows arbitrarily old tokens signed by a trusted issuer to pass authentication [CWE-613: Insufficient Session Expiration]. The issue affects ZITADEL versions prior to 3.4.12 and 4.15.2.
Critical Impact
An attacker holding a previously issued or replayed JWT from a trusted external IdP can bypass token age enforcement and authenticate to ZITADEL regardless of how old the token is.
Affected Products
- ZITADEL versions prior to 3.4.12
- ZITADEL versions prior to 4.15.2
- Deployments configured with external JWT Identity Providers
Discovery Timeline
- 2026-07-10 - CVE-2026-56664 published to the National Vulnerability Database (NVD)
- 2026-07-10 - Last updated in NVD database
Technical Details for CVE-2026-56664
Vulnerability Analysis
ZITADEL supports federated authentication through external JWT Identity Providers. The provider validation routine verifies the token signature, then checks expiration (exp) and issued-at (iat) claims to enforce freshness. The freshness check compares iat against a configured maxAge to reject tokens older than allowed.
The defective logic gated both exp and iat validation behind conditionals that only executed when the claims were non-zero. If the JWT omitted iat, the CheckIssuedAt call was skipped and the maxAge policy was silently bypassed. A valid-signature token from a trusted issuer therefore authenticated successfully no matter its true age.
Because the attack requires a signed token from a trusted issuer and hinges on claim omission, exploitation complexity is elevated and the impact is scoped to confidentiality and integrity at low levels.
Root Cause
The root cause is conditional enforcement of security-critical claims. Treating a missing iat as "skip the check" rather than "reject the token" collapses the freshness guarantee. Any actor able to obtain or reuse a signed JWT without an iat claim from a federated issuer can extend the token's usable lifetime indefinitely.
Attack Vector
An attacker with access to an old JWT from a configured trusted external IdP, or the ability to influence issuance to strip the iat claim, can present the token to ZITADEL's JWT IdP endpoint. ZITADEL validates the signature, observes the missing iat, skips freshness enforcement, and issues a session.
// Vulnerable pattern (pre-patch) in internal/idp/providers/jwt/session.go
// Freshness checks were skipped when claims were zero/missing.
- if !claims.GetExpiration().IsZero() {
- if err = oidc.CheckExpiration(claims, offset); err != nil {
- return nil, fmt.Errorf("%w: expired: %v", ErrInvalidToken, err)
- }
+ if err = oidc.CheckExpiration(claims, offset); err != nil {
+ return nil, fmt.Errorf("%w: expired: %v", ErrInvalidToken, err)
}
- if !claims.GetIssuedAt().IsZero() {
- if err = oidc.CheckIssuedAt(claims, maxAge, offset); err != nil {
- return nil, fmt.Errorf("%w: %v", ErrInvalidToken, err)
- }
+ if err = oidc.CheckIssuedAt(claims, maxAge, offset); err != nil {
+ return nil, fmt.Errorf("%w: %v", ErrInvalidToken, err)
}
// Source: https://github.com/zitadel/zitadel/commit/4925fab849d39a88674485d937b79e54318b48a8
The patch removes the IsZero() guard so CheckExpiration and CheckIssuedAt always execute, forcing rejection when required claims are missing.
Detection Methods for CVE-2026-56664
Indicators of Compromise
- Successful JWT IdP authentications where the presented token lacks an iat claim.
- Authentication events from a federated IdP followed by session activity inconsistent with the user's normal geography or device baseline.
- Repeated logins using tokens with identical jti or signature bytes across long intervals.
Detection Strategies
- Parse ZITADEL authentication logs and flag JWT IdP flows in which iat is absent or predates the configured maxAge window.
- Correlate federated login events with downstream account changes such as role assignments, API key creation, or password resets.
- Alert on any external JWT IdP authentication occurring from ZITADEL versions still below 3.4.12 or 4.15.2.
Monitoring Recommendations
- Enable verbose logging on ZITADEL IdP session handlers and forward events to a centralized SIEM.
- Track the distribution of JWT claim sets over time and treat sudden appearance of tokens without iat as anomalous.
- Monitor internal/idp/providers/jwt/session.go code paths through application performance and audit tooling for failed vs. successful validations.
How to Mitigate CVE-2026-56664
Immediate Actions Required
- Upgrade ZITADEL to version 3.4.12 or 4.15.2 immediately.
- Inventory all configured external JWT Identity Providers and confirm each issuer emits iat and exp claims.
- Rotate signing keys at trusted JWT issuers to invalidate any long-lived tokens that could be replayed.
- Review recent authentication logs for federated logins that occurred without iat present.
Patch Information
The fix is available in ZITADEL Release v3.4.12 and ZITADEL Release v4.15.2. Technical details are documented in the GitHub Security Advisory GHSA-wxg7-w2v3-w38g and the corresponding upstream commit.
Workarounds
- Temporarily disable external JWT IdP configurations until upgrade is complete.
- Restrict trusted JWT issuers to those known to always emit iat and exp claims.
- Enforce short token lifetimes at the IdP layer and require re-authentication for privileged operations.
# Verify running ZITADEL version and upgrade via container image
docker inspect zitadel/zitadel --format '{{.Config.Image}}'
# Pull a patched release
docker pull ghcr.io/zitadel/zitadel:v4.15.2
# or
docker pull ghcr.io/zitadel/zitadel:v3.4.12
# Redeploy and confirm version
zitadel --version
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

