Skip to content

[HOTFIX] fix(tldraw): allow data:image/svg+xml on <image> with recursive sanitization#8088

Merged
MitjaBezensek merged 1 commit intohotfixesfrom
hotfix/dotcom-8087
Feb 25, 2026
Merged

[HOTFIX] fix(tldraw): allow data:image/svg+xml on <image> with recursive sanitization#8088
MitjaBezensek merged 1 commit intohotfixesfrom
hotfix/dotcom-8087

Conversation

@huppy-bot
Copy link
Copy Markdown
Contributor

@huppy-bot huppy-bot bot commented Feb 25, 2026

This is an automated hotfix PR for dotcom deployment.

Original PR: #8087
Original Title: fix(tldraw): allow data:image/svg+xml on with recursive sanitization
Original Author: @MitjaBezensek

This PR cherry-picks the changes from the original PR to the hotfixes branch for immediate dotcom deployment.

/cc @MitjaBezensek


Note

Medium Risk
Touches XSS-hardening logic and changes which data: URIs are permitted on <image>, so mistakes could reintroduce injection vectors or break image rendering; recursion depth limiting reduces worst-case risk.

Overview
sanitizeSvg now allows data:image/svg+xml URLs on <image>/<feImage> by decoding and recursively sanitizing the embedded SVG, then re-encoding it as a data URI; unsafe/invalid embedded SVG (or overly deep nesting) causes the href to be removed.

This introduces helpers for data-URI decode/encode, threads a recursion depth through node/attribute sanitization, and expands tests to cover preserving safe embedded SVG, stripping scripts from mixed-content embeds, and continuing to block fully malicious embeds.

Written by Cursor Bugbot for commit aa36002. This will update automatically on new commits. Configure here.

…ization (#8087)

When you export shapes as SVG, paste back (creates image shape), then
export again with other shapes — the second export wraps the first SVG
as `<image href="data:image/svg+xml;base64,...">`. On paste,
`sanitizeSvg()` strips this href because `sanitizeUri` only allows
raster data URIs on `<image>` elements. Result: blank image.

This PR decodes the embedded SVG, runs `sanitizeSvg()` recursively
(strips scripts/XSS), then re-encodes. Fully malicious embedded SVGs (no
safe content left) are still blocked. Also adds a `MAX_NODE_DEPTH=100`
cap on `sanitizeNode` recursion to prevent DoS from deeply nested
elements.

### Change type

- [x] `bugfix`

### Test plan

1. Export a geo shape as SVG
2. Paste it back (creates image shape)
3. Select that image shape + another shape, export as SVG
4. Paste the resulting SVG — the image should render correctly, not be
blank

- [x] Unit tests

### Release notes

- Fixed SVG sanitizer stripping embedded SVG data URIs on `<image>`
elements. Nested SVGs (from re-exporting pasted SVG images) are now
recursively sanitized instead of blocked.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches XSS-sensitive SVG sanitization logic and introduces recursive
decoding/encoding of data URIs, so subtle parsing/encoding or missed
edge cases could create security or rendering regressions.
> 
> **Overview**
> Fixes a regression where exported SVGs containing nested `<image
href="data:image/svg+xml;base64,...">` were being blanked by the
sanitizer.
> 
> `sanitizeSvg` now allows `data:image/svg+xml` on `<image>`/`<feImage>`
by decoding the embedded SVG, re-running sanitization recursively, and
re-encoding the sanitized result (dropping the `href` entirely if the
embedded SVG has no safe content). Adds an embed recursion depth limit
and new unit tests covering safe embedded SVG preservation and
script-stripping behavior.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
8297037. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
@vercel
Copy link
Copy Markdown

vercel bot commented Feb 25, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
examples Ready Ready Preview Feb 25, 2026 2:11pm
5 Skipped Deployments
Project Deployment Actions Updated (UTC)
analytics Ignored Ignored Preview Feb 25, 2026 2:11pm
chat-template Ignored Ignored Preview Feb 25, 2026 2:11pm
tldraw-docs Ignored Ignored Preview Feb 25, 2026 2:11pm
tldraw-shader Ignored Ignored Preview Feb 25, 2026 2:11pm
workflow-template Ignored Ignored Preview Feb 25, 2026 2:11pm

Request Review

@MitjaBezensek MitjaBezensek merged commit 88223c9 into hotfixes Feb 25, 2026
17 checks passed
@MitjaBezensek MitjaBezensek deleted the hotfix/dotcom-8087 branch February 25, 2026 14:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant