Files
zemion 0c7736dbc3
Verify / verify (push) Canceled after 0s
Release SVG Tools 0.2.0
2026-09-02 04:48:12 +02:00

3.8 KiB

Security model

SVG is active content. Threats include script/event execution, navigation, external fetches and tracking, CSS resource resolution, foreignObject, native animation triggers, namespace confusion, entity/DOCTYPE processing, parser differentials, oversized compressed/data content and algorithmic complexity.

Source and projection

Canonical source is inert text and remains available even when unsafe. A separate projection is built from a cloned semantic document. DOMPurify's SVG profiles are followed by an application policy that:

  • removes script, foreignObject, animate, animateMotion, animateTransform, set, foreign namespaces and all on* attributes;
  • disables links/navigation and executable or external URL attributes;
  • allows only unique local fragment references and bounded base64 raster image data (png, jpeg, gif, webp, avif);
  • parses style declarations/stylesheets with css-tree and rejects @import, unsafe legacy properties, parse failures, non-local URLs, expression() and resource-producing functions such as image-set() and paint();
  • reports findings with source ranges wherever a semantic node/range exists.

DOCTYPE is excluded before DOM parsing; entity declarations invalidate the semantic projection. Sanitized export removes temporary mapping attributes. Sanitize is never applied to canonical source without preview and acceptance.

Isolated preview

The projection is an iframe srcdoc with sandbox="allow-scripts" and no allow-same-origin, giving it an opaque origin. Its child CSP is:

default-src 'none'; connect-src 'none'; object-src 'none'; frame-src 'none';
base-uri 'none'; form-action 'none'; img-src data: blob:;
style-src 'unsafe-inline'; script-src <controller-origin>

The sole script is the packaged canvas-frame-controller.js. It is loaded with anonymous CORS, accepts messages only from parent with a random channel, validates message fields and removes its script element. The parent validates both event.source and channel.

Because a sandbox without same-origin treats the script request as cross-origin, serve this one app-relative asset with:

Access-Control-Allow-Origin: *
Cross-Origin-Resource-Policy: cross-origin

Keep Cross-Origin-Resource-Policy: same-origin for other files. Use an Nginx map/header value, not a nested location that would drop inherited security headers. Toolbox Portal 0.10.0 implements and tests this exception.

Limits and tests

Hard limits are defined in src/app/limits.ts. SVGZ uses streaming decompression and stops once output crosses the source limit. Workers are revisioned, timed out and cancelable. Tree/diagnostic rendering is capped.

Project-authored tests cover script, handlers, links, external image/use/filter, CSS imports/URLs/parser failures/resource functions, native animation, namespaces, duplicate IDs/cycles, malformed entities/XML, depth/attribute/path and data limits. Browser tests assert no script callback and no request to the hostile domain.

Limitations and reporting

This policy protects this application's projections and exports; it is not a general guarantee for arbitrary downstream embedding. Browser SVG/CSS parsers and DOMPurify remain dependency/security boundaries. Bounded data URLs may still decode expensive images within the raster-pixel limits. CSP header regressions can break the fixed controller even when the content remains inert.

DOMPurify is pinned in the lockfile and its SVG policy is covered by the project-authored adversarial suite. Dependency updates must run both npm run test:security and the browser tests before release.

Report vulnerabilities privately through the repository owner/contact before opening a public issue when disclosure could expose users. Include the SVG, browser, deployment headers and observed network/execution behavior without sensitive user files.