Bug #11494
AI spotted security issue VirtualDesktopWebHandler.handleSsoReauth
Start date:
Due date:
% Done:
0%
billable:
No
vendor_id:
GCD
case_num:
version_reported:
version_resolved:
History
#1 Updated by Sergey Ivanovskiy 2 months ago
- File issue_8.txt
added
Please check if it is a real issue.
#2 Updated by Sergey Ivanovskiy about 2 months ago
- File issue_9.txt
added
New issue that can be fixed in this task too.
#3 Updated by Sergey Ivanovskiy about 2 months ago
- File issue_10.txt
added
I will delegate this issue to this task.
#4 Updated by Stefanel Pezamosca about 2 months ago
- Assignee set to Stefanel Pezamosca
Thanks for reporting this, there are some good points here. I'll handle it.
#5 Updated by Hynek Cihlar about 2 months ago
Sergey, please don't add notes in the form of txt attachments. First it is hard to read through and second I don't think the attachments are included in the full text search index.
#6 Updated by Stefanel Pezamosca about 2 months ago
I'll post the contents here:
- [MAJOR] functional
SsoReauth.handleSsoReauth: postMessage contract has no nonce or session identifier — any frame onserverOrigin(e.g. compromised iframe, XSS) can fake{type:'sso-reauth-success'}and dismiss the overlay without an actual re-auth. Include a server-issued state/nonce that ties the message to the in-progress reauth.
PROPOSED FIX:
Have the server generate a cryptographic nonce when issuingMSG_SSO_REAUTH, embed it as the OIDCstateon thereauthUrland validate it inhandleReauthCallback; emit the same nonce back to the opener inside the postMessage payload (and never use'*'as targetOrigin). On the client, capture the nonce fromMSG_SSO_REAUTH, validateevent.data.nonce === expectedNoncebefore treating any message as authoritative, and reject mismatches.
- [MAJOR] functional
SsoReauth.btnRelogin.onclick: Aftersso-reauth-failedthe user is invited to click Re-login again, but the capturedreauthUrl(sso_reauth.js:137) contains the same OIDCstateparameter;OidcSsoAuthenticator.processReauthCallbackat line 347 callslookupAndRemoveReauthState(state)BEFORE the token exchange, consuming the state on the first/reauthcbhit. Any retry returns "Invalid or expired re-auth state". The client must request a fresh re-auth URL (or the server must keep the state until exchange succeeds).
PROPOSED FIX:
Move the lookupAndRemoveReauthState() call so it executes only on a successful token exchange. The state remains valid for the user's second Re-login attempt if the first OIDC exchange fails; on success the state is consumed exactly once. This is preferred over (a) and (b) because it requires no extra round trip or new message type and keeps the existing reauthUrl reusable until success.
- [MAJOR] functional
SsoReauth.handleSsoReauth: No re-entrancy guard. TwoMSG_SSO_REAUTHmessages in quick succession bothawait cleanupReauthUi(true)(idempotent viathat.closed) and both reach thenew p2j.ModalDialog('p2j-sso-reauth-dialog', ...)at sso_reauth.js:156. The secondnew Dialog({id: that.id})at p2j.js:2013-2015 conflicts in the dijit registry.
PROPOSED FIX:
Add a module-scope inProgress Promise that serializes handleSsoReauth invocations. The second concurrent call awaits the first to complete before constructing its own dialog, eliminating the race window between cleanupReauthUi resolving and the new ModalDialog/dijit registration. The promise is cleared in a finally block so success and failure paths both release the lock.