export function escapeHtml(str: string | undefined | null): string { if (str === undefined || str === null) return ""; return String(str) .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } /** * Sanitize a URL to prevent javascript: and data: URL injection * Only allows http:, https:, relative paths, and protocol-relative URLs */ export function sanitizeUrl(url: string | undefined | null): string { if (!url) return ""; const trimmed = url.trim(); const lowerUrl = trimmed.toLowerCase(); // Block dangerous protocols if ( lowerUrl.startsWith("javascript:") || lowerUrl.startsWith("data:") || lowerUrl.startsWith("vbscript:") ) { return ""; } // Allow safe protocols and relative URLs if ( lowerUrl.startsWith("http://") || lowerUrl.startsWith("https://") || lowerUrl.startsWith("mailto:") || lowerUrl.startsWith("tel:") || lowerUrl.startsWith("/") || !lowerUrl.includes(":") ) { return escapeHtml(trimmed); } return ""; }