Why External SVGs Taint Canvas and Block Export
When an external Scalable Vector Graphic (SVG) is drawn onto an HTML5
canvas without proper cross-origin permissions, the browser marks the
canvas as “tainted” to enforce the Same-Origin Policy. Once tainted, the
canvas restricts sensitive data export operations, preventing developers
from calling methods like toDataURL(),
toBlob(), or getImageData(). These
restrictions exist to protect user privacy, prevent unauthorized
cross-origin data exfiltration, and eliminate vulnerabilities arising
from the complex XML architecture of SVG files.
The Same-Origin Policy and the Origin-Clean Flag
The primary mechanism blocking canvas export is the browser’s
Same-Origin Policy. Every HTML5 <canvas> element
maintains an internal boolean flag known as the “origin-clean” flag.
When a canvas is initially created, this flag is set to
true. However, loading and drawing an image, SVG, or video
from a different origin (a different domain, protocol, or port) without
explicit permission immediately sets the origin-clean flag to
false. Once this flag is flipped, the canvas becomes
tainted. Calling data-extraction APIs on a tainted canvas causes the
browser to throw a SecurityError DOMException and halt
script execution.
Specific Security Risks of External SVGs
Unlike standard raster images (such as PNG or JPEG), SVGs are structured XML documents that support dynamic features, styling, external references, and nested markup. Exporting canvas pixel data from an external SVG exposes distinct security threats:
- Cross-Origin Data Exfiltration: If users are logged
into an external service, an SVG hosted on that service might render
personalized, sensitive data. If an attacker could load this external
SVG onto a canvas and read its pixels via
getImageData(), they could steal private information across origins. - CSS History Sniffing: SVGs can utilize CSS
pseudo-classes like
:visited. If pixel data could be read back, malicious scripts could render links inside an SVG, draw it onto a canvas, and determine the user’s browsing history based on the color of rendered pixels. - Subresource and Font Leakage: SVGs can reference external web fonts, external stylesheets, and nested image files. Reading rendered canvas pixels could reveal whether specific local fonts or authenticated remote resources are present on the client system.
- The
<foreignObject>Attack Vector: SVGs can embed arbitrary HTML content using the<foreignObject>tag. Allowing arbitrary HTML rendering followed by pixel extraction creates significant risks regarding credential theft and visual interface spoofing.
Browser Sandbox Restrictions for SVGs
To mitigate risks, web browsers render SVG images inside an isolated
sandbox when they are loaded through an <img> tag or
drawn to a canvas:
- Script Execution is Disabled:
<script>tags and inline JavaScript handlers (such asonloadoronclick) within the SVG are disabled. - External Resource Blocking: Many browsers block an SVG from fetching external subresources (such as external images or stylesheets) when the SVG itself is treated as an image.
- CORS Requirement: If the SVG is fetched from an
external origin, the hosting server must supply the
Access-Control-Allow-OriginHTTP header.
Even if an SVG adheres to sandboxing rules, failing to satisfy Cross-Origin Resource Sharing (CORS) requirements will permanently taint the destination canvas.
Exporting Canvas with External SVGs Safely
To draw an external SVG onto a canvas while keeping the canvas exportable, the external resource must be handled in compliance with CORS standards:
Serve with CORS Headers: The server hosting the SVG must include an
Access-Control-Allow-Originresponse header matching the requesting domain or a wildcard (*).Set the CrossOrigin Attribute: In JavaScript, the
crossOriginproperty of theImageobject must be explicitly declared before setting itssrc:const img = new Image(); img.crossOrigin = "anonymous"; img.src = "https://example.com/graphic.svg"; img.onload = () => { ctx.drawImage(img, 0, 0); const dataURL = canvas.toDataURL(); // Succeeds without SecurityError };Inline SVG Data: Alternatively, the SVG code can be parsed, sanitized, converted into a base64 Data URI, or rendered directly as inline elements within the DOM to bypass cross-origin network constraints entirely.