ITADN

Security: Open redirect via unvalidated redirect_to param in SocialLanding page

#8903OpenShivam8584 创建于 2026-05-29
S
Shivam8584commented
## Summary The `useSocialLandingHandler` hook in `packages/experience/src/pages/SocialLanding/use-social-landing-handler.ts` reads the `redirect_to` query parameter from the URL and passes it directly to `window.location.replace(new URL(redirectUri))` without validating that the destination is same-origin. This creates an open redirect vulnerability via the social sign-in landing page. ## Affected file [`packages/experience/src/pages/SocialLanding/use-social-landing-handler.ts`](https://github.com/logto-io/logto/blob/master/packages/experience/src/pages/SocialLanding/use-social-landing-handler.ts) ## Vulnerable code ```ts const socialLandingHandler = useCallback( (connectorId: string) => { const redirectUri = getSearchParameters(search, SearchParameters.RedirectTo); if (!redirectUri) { setLoading(false); setToast(t('error.invalid_connector_request')); return; } // ... window.location.replace(new URL(redirectUri)); // ← no origin validation }, [search, setToast, t] ); ``` `getSearchParameters` is a simple `URLSearchParams.get()` wrapper. The value is taken directly from `?redirect_to=` in the URL and passed to `window.location.replace` with no same-origin check. ## Impact An attacker can craft a social landing URL pointing to an external domain: ``` https://auth.example.com/social-landing/google?redirect_to=https://attacker.com ``` After a user completes social authentication and lands on this page, they are silently redirected to the attacker-controlled domain. This enables phishing attacks where the user believes they have successfully authenticated and are being returned to the app, but instead are sent to a lookalike page. ## Fix Validate that the redirect target is same-origin before redirecting: ```ts const socialLandingHandler = useCallback( (connectorId: string) => { const redirectUri = getSearchParameters(search, SearchParameters.RedirectTo); if (!redirectUri) { setLoading(false); setToast(t('error.invalid_connector_request')); return; } // Validate same-origin to prevent open redirect try { const url = new URL(redirectUri); if (url.origin !== window.location.origin) { setLoading(false); setToast(t('error.invalid_connector_request')); return; } window.location.replace(url); } catch { setLoading(false); setToast(t('error.invalid_connector_request')); } }, [search, setToast, t] ); ``` ## Note on existing validation The `useRedirectCallbackValidation` hook (`use-redirect-callback-validation.ts`) in the same codebase validates redirect URIs against registered app redirect URIs — but that validation applies to the final OIDC `redirect_uri`, not to this intermediate social landing `redirect_to` parameter. The `useGlobalRedirectTo` hook (`use-global-redirect-to.ts`) intentionally allows external URLs (for social provider redirects and OIDC callbacks to registered app URIs) — but the social landing `redirect_to` parameter should be Logto-internal and same-origin. ## Environment - Logto version: latest (`svhd/logto:latest`, digest `sha256:9dc15595766961d0d81d1026fc38294eacf3ce32d6dab2e9dbeb6d9b10e7a031`) - Confirmed in minified bundle `assets/index-BpICSbS-.js` and source `use-social-landing-handler.ts`
0 条评论