ICONS ONLY right now. No PDFs, no fonts, and no PNGs. 💜
Everything in the Icons tool will stay 100% SVG-only (browse + generate + copy/download). I’ll tighten it so every SVG is sanitized and guaranteed to be SVG before users can copy or download.

Here’s a tiny update set (drop-in) to lock that in:

1) Add client-side SVG sanitization

src/utils/svg.ts — append this helper (keep your existing applySvgColor):

/**
 * sanitizeSvgClient
 * - Removes scripts/foreignObject and event handlers from inline SVGs
 * - Ensures a viewBox and strips width/height so it scales nicely in apps (PPT, Keynote, Slides)
 * - Returns a trimmed <svg>…</svg> string or throws on invalid input
 */
export function sanitizeSvgClient(input: string): string {
  if (!input || typeof input !== "string") throw new Error("Invalid SVG");
  let s = input.trim();

  // Must be an SVG root element
  if (!/^<svg[\s>]/i.test(s)) throw new Error("Not an SVG");

  // Remove xml / doctype
  s = s.replace(/<\?xml[^>]*>/gi, "");
  s = s.replace(/<!DOCTYPE[^>]*>/gi, "");

  // Remove script & foreignObject
  s = s.replace(/<script[\s\S]*?<\/script>/gi, "");
  s = s.replace(/<foreignObject[\s\S]*?<\/foreignObject>/gi, "");

  // Strip event handlers (onload, onclick, etc.)
  s = s.replace(/\son[a-z]+\s*=\s*"[^"]*"/gi, "");
  s = s.replace(/\son[a-z]+\s*=\s*'[^']*'/gi, "");
  s = s.replace(/\son[a-z]+\s*=\s*[^ >]*/gi, "");

  // Remove external hrefs
  s = s.replace(/\s(xlink:)?href\s*=\s*"https?:[^"]*"/gi, "");
  s = s.replace(/\s(xlink:)?href\s*=\s*'https?:[^']*'/gi, "");

  // Ensure viewBox
  if (!/viewBox=/.test(s)) {
    s = s.replace(/<svg([^>]*)>/i, (_m, g1) => `<svg${g1} viewBox="0 0 24 24">`);
  }

  // Drop fixed width/height so it’s responsive/recolorable in apps
  s = s.replace(/\swidth\s*=\s*"[^"]*"/gi, "");
  s = s.replace(/\sheight\s*=\s*"[^"]*"/gi, "");

  return s.trim();
}

2) Use the sanitizer on Copy/Download (Icons page)

src/pages/business-assets/stock/Icons.tsx — update the two places where we export/copy SVG:

Find both onClick handlers that do copyToClipboard(applySvgColor(...)) and downloadTextFile(..., applySvgColor(...)) and wrap them like this:

import { applySvgColor, sanitizeSvgClient } from "../../../utils/svg";

// ...

const safeColored = sanitizeSvgClient(applySvgColor(icon.svg, color));

// Copy button
onClick={() => copyToClipboard(safeColored)}

// Download button
onClick={() => downloadTextFile(`${icon.name}.svg`, safeColored)}


Do the same in the Generate pane:

{genSvg && copyToClipboard(sanitizeSvgClient(applySvgColor(genSvg, color)))}
{genSvg && downloadTextFile(`generated-icon.svg`, sanitizeSvgClient(applySvgColor(genSvg, color)))}


That’s it — now every path from DB → Preview → Copy/Download and Generate → Copy/Download is SVG-only and sanitized before leaving the browser.

3) (Optional, safe) Block any non-SVG responses from the API

We already sanitize on the server (in /api/icons/generate). If you later add /api/icons/search, do the same check:

if (!svg.trim().startsWith("<svg")) return res.status(422).json({ error: "Non-SVG asset blocked." });

Where we stand

Browse: SVGs only, recolorable, favorites (local), with client-side sanitize.

Generate: Calls /api/icons/generate → returns clean SVG → sanitized again on client before export.

Exports: Copy SVG and Download SVG only. No PNG/PDF, no fonts.