diff --git a/apps/web/src/lib/auth-redirect.spec.ts b/apps/web/src/lib/auth-redirect.spec.ts index ba7170b2..2dca7ff8 100644 --- a/apps/web/src/lib/auth-redirect.spec.ts +++ b/apps/web/src/lib/auth-redirect.spec.ts @@ -14,6 +14,11 @@ describe('resolveAuthCallbackURL', () => { null, 'chat', '//evil.example', + '/..//evil.com', + '/..//evil.com/x', + '/./..//evil.com', + '/../..//evil.com', + '/foo/..//evil.com', '/\\evil.example', '/\n//evil.example', '/\r//evil.example', diff --git a/apps/web/src/lib/auth-redirect.ts b/apps/web/src/lib/auth-redirect.ts index 74b24d0b..e9725ac0 100644 --- a/apps/web/src/lib/auth-redirect.ts +++ b/apps/web/src/lib/auth-redirect.ts @@ -12,7 +12,9 @@ export function resolveAuthCallbackURL(candidate: string | null, currentOrigin: try { const expectedOrigin = new URL(currentOrigin).origin; const resolved = new URL(candidate, expectedOrigin); - if (resolved.origin !== expectedOrigin) return DEFAULT_AUTH_CALLBACK_URL; + if (resolved.origin !== expectedOrigin || resolved.pathname.startsWith('//')) { + return DEFAULT_AUTH_CALLBACK_URL; + } return `${resolved.pathname}${resolved.search}${resolved.hash}`; } catch {