Under the Hood: The Architecture of Vector SVG Code Sanitizer & Bloat Stripper
Cloud SVG optimizers take proprietary artwork and often execute or store the XML. That is the wrong trust boundary. Sanitizing vector graphics is XSS prevention: SVGs are XML documents that browsers may execute when inlined. Attackers use <script>, onload=, xlink:href=javascript:…, and HTML inside foreignObject. Security write-ups keep showing that deleting only <script> tags is insufficient. This sanitizer is a local DOM rewrite, not a “prettier” that uploads to a compress API.
Optimize SVG code is a secondary pass: comments, editor metadata, and extra whitespace. That pass is optional so you can keep <title> for accessibility. DOMParser + XMLSerializer + FileReader/Blob are the native APIs. No canvas rasterization—output remains vector.
Memory Allocation & Browser Threading Mechanics
Parsing allocates a document tree proportional to node count. DFS walk is stack-recursive over children; icon SVGs are shallow. Attributes are copied with spread ([...node.attributes]) because live NamedNodeMap mutates while you delete on* names. Serialization emits one string. Main thread is correct; a Worker cannot use DOMParser in all browsers the same way without a document. For multi-megabyte map SVGs, expect a brief parse hitch rather than a network round-trip.
Algorithmic Deep-Dive: Code Snippet & Logical Analysis
function sanitizeSvg(source, stripForeign, stripBloat) {
const doc = new DOMParser().parseFromString(source, "image/svg+xml");
if (doc.querySelector("parsererror")) throw new Error("Could not parse SVG.");
doc.querySelectorAll("script").forEach((n) => n.remove());
if (stripForeign) doc.querySelectorAll("foreignObject").forEach((n) => n.remove());
const walk = (node) => {
for (const attr of [...node.attributes]) {
if (/^on/i.test(attr.name)) node.removeAttribute(attr.name);
if (/href$/i.test(attr.name) && /^\s*(javascript|data):/i.test(attr.value)) {
node.removeAttribute(attr.name);
}
}
if (stripBloat && (node.localName === "metadata" || node.localName === "title")) node.remove();
[...node.children].forEach(walk);
};
walk(doc.documentElement);
let xml = new XMLSerializer().serializeToString(doc);
if (stripBloat) xml = xml.replace(/<!--[\s\S]*?-->/g, "");
return xml;
}parsererror is how Gecko/WebKit surface XML failures; throwing beats silently serializing an error document as if it were art. data: hrefs are removed because they can embed HTML or SVG-in-SVG. External http(s) hrefs on <use> are a remaining policy choice—this pass focuses on executable schemes. Always re-review SVGs that reference remote sprites.
The Local Storage Sandbox & Volatile Data Pipelines
Output is a Blob image/svg+xml downloaded via object URL, then revoked. The parsed Document becomes unreachable after the function returns. Input textarea state is the only persistence, and it is RAM-only.
Verifying True Privacy: How to Audit Your Browser's Network Tab
Clear Network, paste an SVG containing <script>alert(1)</script>, sanitize, download. The markup must not appear in any POST. If the SVG referenced an external https:// image, a later preview might fetch it—this sanitizer’s serialize step does not. Audit both Network and the output source.