* chore: bump version to 2.21.12 and implement safe redirect path validation

- Updated application version from 2.21.11 to 2.21.12 in package.json.
- Introduced `getSafeRedirectPath` and `isSafeRedirectPath` utility functions to validate user-supplied redirect URLs, enhancing security against open redirect attacks.
* fix: address page reload issue in Admin tests for CI
This commit is contained in:
Giancarlo Buomprisco
2025-12-09 23:34:10 +08:00
committed by GitHub
parent 2f78e16dfa
commit 44137016cb
15 changed files with 128 additions and 31 deletions

View File

@@ -1,6 +1,7 @@
import Link from 'next/link';
import { SignInMethodsContainer } from '@kit/auth/sign-in';
import { getSafeRedirectPath } from '@kit/shared/utils';
import { Button } from '@kit/ui/button';
import { Heading } from '@kit/ui/heading';
import { Trans } from '@kit/ui/trans';
@@ -29,7 +30,7 @@ async function SignInPage({ searchParams }: SignInPageProps) {
const paths = {
callback: pathsConfig.auth.callback,
returnPath: next || pathsConfig.app.home,
returnPath: getSafeRedirectPath(next, pathsConfig.app.home),
joinTeam: pathsConfig.app.joinTeam,
};

View File

@@ -1,6 +1,7 @@
import { redirect } from 'next/navigation';
import { MultiFactorChallengeContainer } from '@kit/auth/mfa';
import { getSafeRedirectPath } from '@kit/shared/utils';
import { checkRequiresMultiFactorAuthentication } from '@kit/supabase/check-requires-mfa';
import { getSupabaseServerClient } from '@kit/supabase/server-client';
@@ -38,7 +39,7 @@ async function VerifyPage(props: Props) {
}
const nextPath = (await props.searchParams).next;
const redirectPath = nextPath ?? pathsConfig.app.home;
const redirectPath = getSafeRedirectPath(nextPath, pathsConfig.app.home);
return (
<MultiFactorChallengeContainer

View File

@@ -3,6 +3,7 @@ import { Metadata } from 'next';
import { redirect } from 'next/navigation';
import { AuthLayoutShell } from '@kit/auth/shared';
import { getSafeRedirectPath } from '@kit/shared/utils';
import { requireUser } from '@kit/supabase/require-user';
import { getSupabaseServerClient } from '@kit/supabase/server-client';
import { Heading } from '@kit/ui/heading';
@@ -96,7 +97,7 @@ async function fetchData(props: IdentitiesPageProps) {
}
// Get the next path from URL params (where to redirect after setup)
const nextPath = searchParams.next || pathsConfig.app.home;
const nextPath = getSafeRedirectPath(searchParams.next, pathsConfig.app.home);
// Available auth methods to add
const showPasswordOption = authConfig.providers.password;

View File

@@ -130,7 +130,8 @@ export async function GET(request: NextRequest) {
joinUrl.searchParams.set('is_new_user', 'true');
}
authCallbackUrl.searchParams.set('next', joinUrl.href);
// Use pathname + search to create a safe relative path for validation
authCallbackUrl.searchParams.set('next', joinUrl.pathname + joinUrl.search);
logger.info(
{

View File

@@ -2,6 +2,7 @@ import { redirect } from 'next/navigation';
import { UpdatePasswordForm } from '@kit/auth/password-reset';
import { AuthLayoutShell } from '@kit/auth/shared';
import { getSafeRedirectPath } from '@kit/shared/utils';
import { requireUser } from '@kit/supabase/require-user';
import { getSupabaseServerClient } from '@kit/supabase/server-client';
@@ -38,7 +39,7 @@ async function UpdatePasswordPage(props: UpdatePasswordPageProps) {
}
const { callback } = await props.searchParams;
const redirectTo = callback ?? pathsConfig.app.home;
const redirectTo = getSafeRedirectPath(callback, pathsConfig.app.home);
return (
<AuthLayoutShell Logo={Logo}>

View File

@@ -4,6 +4,7 @@ import { NextResponse } from 'next/server';
import { CsrfError, createCsrfProtect } from '@edge-csrf/nextjs';
import { isSuperAdmin } from '@kit/admin';
import { getSafeRedirectPath } from '@kit/shared/utils';
import { checkRequiresMultiFactorAuthentication } from '@kit/supabase/check-requires-mfa';
import { createMiddlewareClient } from '@kit/supabase/middleware-client';
@@ -158,8 +159,10 @@ async function getPatterns() {
// If user is logged in and does not need to verify MFA,
// redirect to home page.
if (!isVerifyMfa) {
const nextPath =
req.nextUrl.searchParams.get('next') ?? pathsConfig.app.home;
const nextPath = getSafeRedirectPath(
req.nextUrl.searchParams.get('next'),
pathsConfig.app.home,
);
return NextResponse.redirect(
new URL(nextPath, req.nextUrl.origin).href,