Skip to content

Commit a489e7d

Browse files
fix: don't crash the server on URI paths with invalid percent-encoding
Scanner requests like /chat/..%c0%af..%c0%afetc/passwd or /chat/WEB-INF/web.xml%C0%80.jsp killed prod pods: SvelteKit calls the handle hook even when the pathname fails to decode (it only produces the 400 Malformed URI error inside resolve()), so the OAuth login branch ran first and its thrown redirect() ended up as an unhandled promise rejection, which terminates the Node process. Two changes: - handle hook rejects paths with invalid percent-encoding with a plain 400 before any auth/OAuth logic - triggerOauthFlow returns a real 302 Response instead of throwing a Redirect, so it can never surface as an unhandled rejection Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent f4ed195 commit a489e7d

2 files changed

Lines changed: 16 additions & 2 deletions

File tree

src/lib/server/auth.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { config } from "$lib/server/config";
1212
import { sha256 } from "$lib/utils/sha256";
1313
import { z } from "zod";
1414
import { dev } from "$app/environment";
15-
import { redirect, type Cookies } from "@sveltejs/kit";
15+
import { type Cookies } from "@sveltejs/kit";
1616
import { collections } from "$lib/server/database";
1717
import JSON5 from "json5";
1818
import { logger } from "$lib/server/logger";
@@ -580,5 +580,9 @@ export async function triggerOauthFlow({ url, locals, cookies }: RequestEvent):
580580
{ sessionId: locals.sessionId, next, url, cookies }
581581
);
582582

583-
throw redirect(302, authorizationUrl);
583+
// Return a real 302 response instead of `throw redirect(...)`: this
584+
// function is called from the handle hook, where a thrown Redirect that
585+
// crosses an unawaited promise boundary becomes an unhandled rejection
586+
// and kills the Node process (observed in prod with scanner requests).
587+
return new Response(null, { status: 302, headers: { location: authorizationUrl } });
584588
}

src/lib/server/hooks/handle.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,16 @@ export async function handleRequest({ event, resolve }: HandleInput): Promise<Re
5959
});
6060
}
6161

62+
// Reject URI paths with invalid percent-encoding (e.g. overlong UTF-8
63+
// like %c0%af used by path-traversal scanners) before any further
64+
// processing. SvelteKit only turns these into a 400 inside resolve();
65+
// the OAuth redirect logic below runs earlier and must not see them.
66+
try {
67+
decodeURIComponent(event.url.pathname);
68+
} catch {
69+
return errorResponse(400, "Malformed URI");
70+
}
71+
6272
if (event.route.id === "/admin" || event.route.id?.startsWith("/admin/")) {
6373
const ADMIN_SECRET = config.ADMIN_API_SECRET || config.PARQUET_EXPORT_SECRET;
6474

0 commit comments

Comments
 (0)