Skip to content

fix: mitigate SSO session fixation with postMessage verification#2447

Open
chaitanyapotti wants to merge 3 commits intomasterfrom
fix/sso-session-fixation-postmessage
Open

fix: mitigate SSO session fixation with postMessage verification#2447
chaitanyapotti wants to merge 3 commits intomasterfrom
fix/sso-session-fixation-postmessage

Conversation

@chaitanyapotti
Copy link
Copy Markdown
Member

@chaitanyapotti chaitanyapotti commented Apr 10, 2026

Jira Link

N/A — Security vulnerability report response

Description

Mitigates an SSO session fixation vulnerability in the popup login flow. The attack exploits SecurePubSub's server-side relay architecture: an attacker initiates OAuth, extracts the authorization URL, sends it to a victim, and receives the victim's credentials through the shared SecurePubSub channel.

Changes:

  • Add a postMessage event listener in connectWithSocialLogin that receives login_finished directly from the popup via window.opener.postMessage()
  • Validate the message origin (must match auth service URL) and nonce before accepting
  • Send a WEB3AUTH_LOGIN_ACK back to the popup so it can skip the SecurePubSub dapp channel
  • Retain SecurePubSub as a fallback for browsers where window.opener is unavailable (e.g. COOP headers)

Companion PR: Web3Auth/auth-service — sends the postMessage from the popup callback page and waits for ACK before deciding whether to use SecurePubSub.

How has this been tested?

  • Verified that the postMessage listener correctly validates origin, type, and nonce
  • Verified cleanup of event listeners in all exit paths (success, error, popup closed)
  • SecurePubSub fallback path preserved for backward compatibility

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)

Checklist

  • My code follows the code style of this project. (run lint)
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

Note

High Risk
Changes the OAuth popup completion path in AuthConnector.connectWithSocialLogin, which is part of the authentication flow and security-sensitive. Incorrect origin/nonce handling or cleanup could break logins or reintroduce session-fixation style issues.

Overview
Mitigates a popup OAuth session-fixation vector by preferring a direct window.postMessage signal from the auth-service popup over the shared SecurePubSub relay channel.

connectWithSocialLogin now listens for web3auth_login_finished messages, validates origin (auth service) and nonce, sends a web3auth_login_ack back to the popup, optionally forwards OAuth data to the auth iframe, and centralizes cleanup to ensure listeners/popup/pubsub are closed exactly once while retaining SecurePubSub as a compatibility fallback when window.opener is unavailable.

Reviewed by Cursor Bugbot for commit f7f8365. Bugbot is set up for automated code reviews on this repo. Configure here.

Add postMessage as a secure direct channel between the OAuth popup and
the DApp window, with SecurePubSub retained as a fallback for browsers
where window.opener is unavailable (e.g. COOP headers).

The authConnector now listens for a postMessage from the auth service
popup, validates origin and nonce, and sends an ACK back. If the popup
receives the ACK within 100ms, it skips the SecurePubSub dapp channel
entirely, eliminating the session fixation attack vector.
@chaitanyapotti chaitanyapotti requested a review from a team as a code owner April 10, 2026 13:14
@vercel
Copy link
Copy Markdown

vercel bot commented Apr 10, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
web3auth-web Ready Ready Preview, Comment Apr 13, 2026 4:25am

Request Review

reject(error);
}
isClosedWindow = true;
securePubSub.cleanup();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successful postMessage login triggers false failed audit

Low Severity

When the postMessage path succeeds (no error), handleLoginFinished calls securePubSub.cleanup() while the SecurePubSub .subscribe() promise is still pending. If cleanup() causes the pending subscription to reject, the .catch() handler fires and calls auditOAuditProgress(loginParams, "failed") — recording a false "failed" audit for a login that actually succeeded. In the original code, securePubSub.cleanup() in the success path was only ever called inside the .subscribe().then() callback, meaning the subscription had already resolved and cleanup() couldn't trigger the .catch() handler.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 4dca2b0. Configure here.

Add postMessage as a secure direct channel between the OAuth popup and
the DApp window, with SecurePubSub retained as a fallback for browsers
where window.opener is unavailable (e.g. COOP headers).

The authConnector listens for postMessage from the auth service popup,
validates origin and nonce, sends an ACK back, and forwards the OAuth
data to the Auth iframe. If the popup receives the ACK within 100ms,
it skips SecurePubSub entirely.
…3Auth/web3auth-web into fix/sso-session-fixation-postmessage
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit f7f8365. Configure here.

window.removeEventListener("message", handlePostMessage);
this.authInstance.postLoginCancelledMessage(nonce);
reject(error);
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Window open failure leaves SecurePubSub and state uncoordinated

Low Severity

The verifierWindow.open().catch() handler rejects the promise but does not set loginFinished = true or call securePubSub.cleanup(). Since loginFinished remains false, a later SecurePubSub message or close event can still invoke handleLoginFinished, which calls postLoginCancelledMessage a second time and attempts redundant cleanup on an already-settled promise.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit f7f8365. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant