mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 09:33:46 +00:00
fix(security): extract & reuse getSafeRedirectPath, plug TopUpAmount returnTo
TelegramRedirect already had a local getSafeRedirectUrl helper that
collapsed protocol-relative URLs, absolute URLs, exotic schemes, and
URL-encoded forms down to '/'. TopUpAmount.handleSuccess was navigating
straight to a user-supplied returnTo query param without that filter —
not externally exploitable through react-router's navigate() (it doesn't
trigger an external nav), but a crafted link could produce ugly path
artefacts ('?returnTo=https://evil.com' would land the user at
/balance/top-up/<method>/https://evil.com).
Hoist the helper to src/utils/safeRedirect.ts, rename to
getSafeRedirectPath, reuse it in TelegramRedirect, and wrap TopUpAmount's
returnTo through it before navigate().
This commit is contained in:
31
src/utils/safeRedirect.ts
Normal file
31
src/utils/safeRedirect.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Normalise a user-supplied redirect / returnTo URL down to a safe in-app path.
|
||||
*
|
||||
* Returns the input unchanged when it is a plain absolute path (`/foo/bar`).
|
||||
* Returns `/` otherwise — for protocol-relative URLs (`//evil.com`), absolute
|
||||
* URLs (`https://…`), exotic schemes (`javascript:`, `data:`), or anything
|
||||
* that smuggles a host through URL encoding (`%2F%2Fevil.com`).
|
||||
*
|
||||
* Even with react-router's navigate() — which only treats inputs as paths
|
||||
* and won't trigger an external nav — pasted absolute URLs would still
|
||||
* produce ugly path artifacts. Centralising the check matches what
|
||||
* TelegramRedirect already did and gives every returnTo entry the same
|
||||
* shape.
|
||||
*/
|
||||
export function getSafeRedirectPath(url: string | null | undefined): string {
|
||||
if (!url) return '/';
|
||||
// Only allow relative paths starting with /
|
||||
if (!url.startsWith('/') || url.startsWith('//')) {
|
||||
return '/';
|
||||
}
|
||||
// Catch the encoded forms (//evil.com → %2F%2Fevil.com, scheme://…)
|
||||
try {
|
||||
const decoded = decodeURIComponent(url);
|
||||
if (!decoded.startsWith('/') || decoded.startsWith('//') || decoded.includes('://')) {
|
||||
return '/';
|
||||
}
|
||||
} catch {
|
||||
return '/';
|
||||
}
|
||||
return url;
|
||||
}
|
||||
Reference in New Issue
Block a user