# 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: ```text 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 ``` 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: ```text 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.