diff --git a/src/web/server.ts b/src/web/server.ts index a3cd227..d7ad9e8 100755 --- a/src/web/server.ts +++ b/src/web/server.ts @@ -123,6 +123,21 @@ export function createWebServer(options: WebServerOptions): WebServer { socket.destroy(); return; } + const reqHost = req.headers.host; + const originHeader = req.headers.origin; + if (originHeader) { + let originHost: string | null = null; + try { + originHost = new URL(originHeader).host; + } catch { + // fall through; treat as missing/invalid origin + } + if (!originHost || originHost !== reqHost) { + socket.write("HTTP/1.1 403 Forbidden\r\nConnection: close\r\n\r\n"); + socket.destroy(); + return; + } + } const result = validateSessionFromHeaders(req.headers.cookie as string | undefined, sessions); if (!result) { socket.write("HTTP/1.1 401 Unauthorized\r\nConnection: close\r\n\r\n"); diff --git a/web/src/views/Login.vue b/web/src/views/Login.vue index feb6658..4cad401 100644 --- a/web/src/views/Login.vue +++ b/web/src/views/Login.vue @@ -34,7 +34,8 @@ async function submit() { loading.value = true; try { await session.login(username.value, password.value); - const next = typeof route.query.next === 'string' ? route.query.next : '/'; + const rawNext = typeof route.query.next === 'string' ? route.query.next : '/'; + const next = rawNext.startsWith('/') && !rawNext.startsWith('//') ? rawNext : '/'; router.replace(next); } catch (e) { error.value = (e as Error).message;