From 98a107d4b4eaeab5cbb96ee0a28c2342b853eee0 Mon Sep 17 00:00:00 2001 From: Karl Ludwig Weise Date: Tue, 5 May 2026 11:31:36 +0200 Subject: [PATCH] Prevent admins from entering malicious javascript into link settings --- src/lib/components/ui/button/button.svelte | 22 +++++++++++++++++-- .../server/services/tenant-admin-service.ts | 13 +++++++++-- src/lib/server/utils/url.ts | 6 +++++ .../(components)/edit-settings-form/schema.ts | 11 +++++++++- 4 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/lib/components/ui/button/button.svelte b/src/lib/components/ui/button/button.svelte index a442c51..66da5a5 100644 --- a/src/lib/components/ui/button/button.svelte +++ b/src/lib/components/ui/button/button.svelte @@ -43,6 +43,10 @@ -{#if href} +{#if derivedHref} >, ) { @@ -237,6 +237,15 @@ export class TenantAdminService { throw new ValidationError("Shortname cannot be changed"); } + // Check each link + if (updateData.links) { + for (const link of Object.values(updateData.links)) { + if (!isLinkValid(link)) { + throw new ValidationError("Links must start with http or https or be empty"); + } + } + } + // Check if domain is already in use if (updateData.domain) { const domainExists = await centralDb diff --git a/src/lib/server/utils/url.ts b/src/lib/server/utils/url.ts index 66c4a79..995cea9 100644 --- a/src/lib/server/utils/url.ts +++ b/src/lib/server/utils/url.ts @@ -4,3 +4,9 @@ export const redactDbUrl = (input: string) => { url.password = "redacted-pw"; return url.toString(); }; + +export const isLinkValid = (link: string | undefined) => { + return ( + link?.startsWith("http://") || link?.startsWith("https://") || link === "" || link === undefined + ); +}; diff --git a/src/routes/(pages)/dashboard/settings/(components)/edit-settings-form/schema.ts b/src/routes/(pages)/dashboard/settings/(components)/edit-settings-form/schema.ts index 10419de..58458f9 100644 --- a/src/routes/(pages)/dashboard/settings/(components)/edit-settings-form/schema.ts +++ b/src/routes/(pages)/dashboard/settings/(components)/edit-settings-form/schema.ts @@ -2,7 +2,16 @@ import { m } from "$i18n/messages"; import { z } from "zod"; const optionalUrl = (errorMessage: string) => - z.union([z.literal(""), z.url({ message: errorMessage })]).optional(); + z + .union([ + z.literal(""), + z + .url({ message: errorMessage }) + .refine((url) => url.startsWith("http://") || url.startsWith("https://"), { + message: errorMessage, + }), + ]) + .optional(); export const formSchema = z .object({