From b94ae3cd0f1cf76066bb1bff6fda202bbffa2c7a Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 22 Jul 2026 08:10:57 +0000 Subject: [PATCH] Fix encoded-path auth bypass in example route guard The example protectedRoutesHandle hook guarded on event.url.pathname, which preserves percent-encoding per the WHATWG URL spec. SvelteKit decodes the pathname before matching routes, so a request to /%61ccount skipped the guard yet still dispatched the protected /account route (same for /%61pi/... vs the /api/ guard). Guard on event.route.id (the resolved route) instead, which reflects the matched route and is immune to encoding tricks. --- example/src/hooks.server.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/example/src/hooks.server.ts b/example/src/hooks.server.ts index 3c255a6..d7c44bc 100644 --- a/example/src/hooks.server.ts +++ b/example/src/hooks.server.ts @@ -20,11 +20,20 @@ const authHandle = authKitHandle({ // Create a custom handle for protected routes const protectedRoutesHandle: Handle = async ({ event, resolve }) => { const protectedPaths = ['/account', '/api/'] as const; - const isProtectedRoute = protectedPaths.some((path) => event.url.pathname.startsWith(path)); + // Guard on the resolved route id rather than the raw URL pathname. + // SvelteKit decodes the pathname before matching routes, so a check + // against event.url.pathname (which preserves percent-encoding) can be + // bypassed with an encoded path such as /%61ccount while the router still + // dispatches the protected /account route. event.route.id reflects the + // matched route and is immune to encoding tricks. + const routeId = event.route.id; + const isProtectedRoute = + routeId != null && protectedPaths.some((path) => routeId === path || routeId.startsWith(path)); + const isApiRoute = routeId != null && routeId.startsWith('/api/'); if (isProtectedRoute && !event.locals.auth?.user) { // API routes should return 401 - if (event.url.pathname.startsWith('/api/')) { + if (isApiRoute) { return new Response(JSON.stringify({ error: 'Unauthorized' }), { status: 401, headers: { 'Content-Type': 'application/json' },