The vulnerability is a stored Cross-Site Scripting (XSS) issue in ZITADEL's login interface that could lead to account takeover. The root cause was twofold:
-
Stored XSS via defaultRedirectUri: Organization administrators could configure a defaultRedirectUri. This URI was not properly sanitized before being used in a link's href attribute on the post-login page (/signedin). A malicious administrator could set this URI to a javascript: payload. When a user from that organization logged in, the malicious script would execute in their browser. The vulnerable function is the Page component in apps/login/src/app/(login)/signedin/page.tsx, which rendered this link without validation. The fix was introduced in commit f2d451a by adding the isSafeRedirectUri function to validate the URI and prevent malicious schemes.
-
Password Reset without Current Password: The account takeover was possible because the checkSessionAndSetPassword function allowed changing a password without providing the current one. It only checked if the user had recently authenticated. The XSS payload could be used to trigger this password change process for the logged-in user. The vulnerable function is checkSessionAndSetPassword in apps/login/src/lib/server/password.ts. The fix, implemented in commit 8509cc9, was to modify this function to always require the user's currentPassword for verification before allowing a change.
In summary, an attacker could store a malicious script that, when executed by a victim, would call the insecure password change function to take over the account. The patches address both the XSS vector and the insecure password reset logic.