// Sanitizer SVG focalizzato sul caso "logo del portale caricato dall'admin". // Approccio: rimozione regex-based dei costrutti pericolosi (deny-list aggressiva + // validazione che il contenuto sia davvero SVG). Non è una difesa esaustiva da // payload SVG sofisticati: per quello servirebbe DOMPurify+jsdom o xmldom. // Per il nostro modello di minaccia (admin trusted carica il proprio logo) basta. // Defense-in-depth: il file servito da /api/files include CSP `script-src 'none'` // quando il MIME è image/svg+xml. // Tag che vanno completamente rimossi (anche il contenuto): // - script/foreignObject/iframe/embed/object: codice eseguibile // - style/link/meta: possono caricare risorse esterne o iniettare CSS dannoso // - set/animate*: animation handlers possono triggerare eventi const FORBIDDEN_TAGS = [ 'script', 'foreignObject', 'iframe', 'embed', 'object', 'link', 'meta', 'style', 'set', 'animate', 'animateMotion', 'animateTransform', ] as const; const EVENT_ATTR_RE = /\s+on\w+\s*=\s*("[^"]*"|'[^']*'|\S+)/gi; // href/xlink:href con schema non consentito. // Sono ammessi: #fragment, http(s)://, mailto:, tel:. Tutto il resto via. const UNSAFE_HREF_RE = /\s+(xlink:)?href\s*=\s*("|')\s*(?!#|https?:|mailto:|tel:|\2)[^"']*\2/gi; // Rimuove strighe `javascript:` o `data:text/html` anche dentro attributi che non // passano dal pattern href (es. attributeName, values, ecc.) — best effort. const SCHEME_INLINE_RE = /(javascript:|data:text\/html)/gi; export type SvgSanitizeResult = | { ok: true; sanitized: string } | { ok: false; error: string }; export function sanitizeSvg(input: string): SvgSanitizeResult { if (typeof input !== 'string' || input.length === 0) { return { ok: false, error: 'Empty SVG content.' }; } // Deve essere un documento SVG: opzionalmente un XML declaration, opzionalmente // commenti, e poi un tag . if (!/^\s*(<\?xml[^?]*\?>\s*)?(\s*)*]/i.test(input)) { return { ok: false, error: 'Not a valid SVG document.' }; } let out = input; // 1) Rimuove i tag vietati (sia open+close che self-closing) for (const tag of FORBIDDEN_TAGS) { // ... out = out.replace(new RegExp(`<${tag}\\b[^>]*>[\\s\\S]*?`, 'gi'), ''); // oppure out = out.replace(new RegExp(`<${tag}\\b[^>]*/?>`, 'gi'), ''); } // 2) Rimuove event handler (onload, onclick, onerror, ecc.) out = out.replace(EVENT_ATTR_RE, ''); // 3) Strippa href/xlink:href con schema non ammesso out = out.replace(UNSAFE_HREF_RE, ''); // 4) Rimozione difensiva di `javascript:` / `data:text/html` ovunque appaiano out = out.replace(SCHEME_INLINE_RE, ''); return { ok: true, sanitized: out }; }