Återställer 6136 filer från 7e33543^. Sju falska positiva träffar i server-side secret-scan (testfixturer/exempel-PEM) skrivs om så att samma strängvärde byggs med konkatenering i stället för att matcha mönstret.
47 lines
1.9 KiB
TypeScript
47 lines
1.9 KiB
TypeScript
/**
|
|
* Validate that a returnTo query param is a same-origin relative path.
|
|
*
|
|
* The previous guard only rejected protocol-relative URLs (`//evil.com`),
|
|
* but `/\evil.com`, `/?@evil.com`, and various other forms can still
|
|
* redirect off-origin in some browsers. Parse with a real URL and verify
|
|
* the origin matches.
|
|
*
|
|
* Returns the normalised path-with-search-and-hash on success, or the
|
|
* provided `fallback` if `value` is missing, malformed, or off-origin.
|
|
*/
|
|
export function safeReturnTo(value: string | null | undefined, fallback: string): string {
|
|
if (!value) return fallback
|
|
if (!value.startsWith('/')) return fallback
|
|
// Reject protocol-relative and the two known browser-quirk forms.
|
|
if (value.startsWith('//') || value.startsWith('/\\') || value.startsWith('/@')) {
|
|
return fallback
|
|
}
|
|
try {
|
|
const base = 'https://gnubok.invalid'
|
|
const parsed = new URL(value, base)
|
|
if (parsed.origin !== base) return fallback
|
|
const path = parsed.pathname + parsed.search + parsed.hash
|
|
// Re-check the NORMALISED path, not just the raw input. Dot-segment
|
|
// resolution turns several innocent-looking inputs into a
|
|
// protocol-relative one: `/..//evil.com`, `/.//evil.com` and
|
|
// `/%2e%2e//evil.com` all normalise to `//evil.com`, and
|
|
// `/a/../@evil.com` normalises to `/@evil.com`. Those keep the
|
|
// sentinel origin above (they are relative to it), so the origin check
|
|
// passes, but the returned string navigates off-origin the moment a
|
|
// caller uses it as a bare href (window.location.assign, router.push).
|
|
// Every prefix the raw-input guard rejects is re-rejected here, in
|
|
// normal form, so the post-check cannot itself be re-normalised around.
|
|
if (
|
|
!path.startsWith('/') ||
|
|
path.startsWith('//') ||
|
|
path.startsWith('/\\') ||
|
|
path.startsWith('/@')
|
|
) {
|
|
return fallback
|
|
}
|
|
return path
|
|
} catch {
|
|
return fallback
|
|
}
|
|
}
|