diff --git a/packages/data-provider/src/config.ts b/packages/data-provider/src/config.ts index 66ca300ef0..1e40b44ad6 100644 --- a/packages/data-provider/src/config.ts +++ b/packages/data-provider/src/config.ts @@ -619,7 +619,7 @@ export const interfaceSchema = z .string() .url() .refine(isSafeImageUrl, { - message: 'loginImageUrl must be a valid HTTP or HTTPS URL', + message: 'loginImageUrl must be a valid HTTP, HTTPS, or data:image URL', }) .optional(), loginText: z.string().optional(), diff --git a/packages/data-provider/src/utils.ts b/packages/data-provider/src/utils.ts index bd14302679..7bd7c5375f 100644 --- a/packages/data-provider/src/utils.ts +++ b/packages/data-provider/src/utils.ts @@ -62,14 +62,23 @@ export function normalizeEndpointName(name = ''): string { } /** - * Validates that a URL uses only safe protocols (http or https) + * Validates that a URL uses only safe protocols (http, https, or data:image/*) * @param url - The URL string to validate * @returns true if the URL is safe, false otherwise */ export const isSafeImageUrl = (url: string): boolean => { try { const parsedUrl = new URL(url); - return parsedUrl.protocol === 'http:' || parsedUrl.protocol === 'https:'; + if (parsedUrl.protocol === 'http:' || parsedUrl.protocol === 'https:') { + return true; + } + + if (parsedUrl.protocol !== 'data:') { + return false; + } + + // Restrict data URLs to image payloads only. + return /^data:image\/[a-z0-9.+-]+(?:;[a-z0-9=._+-]+)*(?:;base64)?,/i.test(url); } catch { return false; }