From a7d4745f93a0c0326f4554b5d902a25fb261dca4 Mon Sep 17 00:00:00 2001 From: Jan Kahmen <36455663+kah-ja@users.noreply.github.com> Date: Tue, 15 Sep 2026 09:57:22 +0000 Subject: [PATCH] Only accept http(s) targets for the resource auth redirect The resource auth page copies the redirect query parameter into redirectUrl when its host matches the resource host (src/app/auth/resource/[resourceGuid]/page.tsx:121-150). URL parses a host out of every scheme that uses "//", so a target such as javascript://resource-host/... passes that comparison. The value is handed to ResourceAuthPortal as the redirect prop and assigned to window.location.href after a successful login (src/components/ResourceAuthPortal.tsx:213,247,281). Parse the target once and require http: or https: before the host comparisons. The three branches that assigned the same value are folded into one condition; the accepted set of http(s) targets is unchanged. --- src/app/auth/resource/[resourceGuid]/page.tsx | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/app/auth/resource/[resourceGuid]/page.tsx b/src/app/auth/resource/[resourceGuid]/page.tsx index 318d63517..53217dcfd 100644 --- a/src/app/auth/resource/[resourceGuid]/page.tsx +++ b/src/app/auth/resource/[resourceGuid]/page.tsx @@ -122,11 +122,20 @@ export default async function ResourceAuthPage(props: { if (searchParams.redirect) { try { + const redirectTarget = new URL(searchParams.redirect); const serverResourceHost = new URL(authInfo.url).host; - const redirectHost = new URL(searchParams.redirect).host; - const redirectPort = new URL(searchParams.redirect).port; + const redirectHost = redirectTarget.host; + const redirectPort = redirectTarget.port; const serverResourceHostWithPort = `${serverResourceHost}:${redirectPort}`; + // URL parses a host out of any scheme that uses "//", so a target + // like javascript://resource-host/... matches the comparisons + // below. The target is later assigned to window.location, so only + // http(s) is accepted here. + const isHttpTarget = + redirectTarget.protocol === "http:" || + redirectTarget.protocol === "https:"; + const wildcardMatchesRedirect = ( wildcardDomain: string, host: string @@ -136,14 +145,16 @@ export default async function ResourceAuthPage(props: { return host.endsWith(suffix) && host.length > suffix.length; }; - if (serverResourceHost === redirectHost) { - redirectUrl = searchParams.redirect; - } else if (serverResourceHostWithPort === redirectHost) { - redirectUrl = searchParams.redirect; - } else if ( - authInfo.wildcard && - authInfo.fullDomain && - wildcardMatchesRedirect(authInfo.fullDomain, redirectHost) + if ( + isHttpTarget && + (serverResourceHost === redirectHost || + serverResourceHostWithPort === redirectHost || + (authInfo.wildcard && + authInfo.fullDomain && + wildcardMatchesRedirect( + authInfo.fullDomain, + redirectHost + ))) ) { redirectUrl = searchParams.redirect; }