Uh oh!
There was an error while loading. Please reload this page.
fix(web): render data URI images in chat markdown - #9133
Conversation
Assistant messages embedding images as data: URIs rendered terminal 'Image unavailable' placeholders (pingdotgg#9094): react-markdown's default URL transform empties every data: URL, and the sanitize schema dropped the protocol on img src. Allow data:image/ sources through both layers so inline data images render; non-image data URIs stay blocked. Fixed with Claude Fable 5 on Claude Code.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 6d9e744. Configure here.
Uh oh!
There was an error while loading. Please reload this page.
ApprovabilityVerdict: Not approved Macroscope's review found this PR not approvable — This small fix changes production markdown sanitization and URL handling for untrusted chat content to allow inline image payloads. Despite targeted tests and limited scope, the security-sensitive sanitizer change warrants human validation. Notes:
You can add or adjust custom eligibility rules. Learn more. |
Written by Claude Fable 5 on Claude Code.
CDVolvik
left a comment
There was a problem hiding this comment.
The tests are the useful part: png data URIs stay on src, data:text/html becomes "Image unavailable".
One nit: INLINE_DATA_IMAGE_PATTERN is /^data:image\//i, so data:image/svg+xml counts as an image. The comment says an img never runs scripts. SVG can. If that's accepted, fine; if not, the pattern is wider than png/jpeg/webp/gif.
Didn't run the test file.

Problem
Assistant messages embedding images as
data:URIs render terminalImage unavailableplaceholders (methods 3 and 4 in #9094). Two layers strip them independently: react-markdown'sdefaultUrlTransformempties everydata:URL before rendering, and the chat sanitize schema does not allow thedataprotocol onimg src.The path-based delivery methods from #9094 were fixed by #9023's
media-fileasset flow; inline data images are the remaining gap.Fix
Allow
data:image/sources through both layers — the markdown URL transform and the sanitize schema — scoped to image payloads only. An<img>never executes scripts, and non-imagedata:URIs keep rendering the blocked-image fallback (covered by a new test).Verification
data:text/htmlstays blocked.vp test run apps/web/src/components/ChatMarkdown.workspace-images.test.tsx— 26 passed.Closes#9094.
Written by Claude Fable 5 on Claude Code.
Note
Medium Risk
Changes markdown sanitization and URL handling for user-controlled chat content, though scope is limited to image data URIs on img tags.
Overview
Chat markdown now renders inline
data:image/*embeds instead of showing Image unavailable, for both markdown![]()and raw<img>sources.The fix touches two layers that previously stripped all
data:URLs:CHAT_MARKDOWN_SANITIZE_SCHEMAallows thedataprotocol onimgsrc, andmarkdownUrlTransformpassesdata:image/hrefs through unchanged (viaINLINE_DATA_IMAGE_PATTERN) instead of running them throughdefaultUrlTransform.Non-image
data:payloads (e.g.data:text/html) still render the blocked-image fallback; new tests cover allowed image URIs and rejected non-image URIs.Reviewed by Cursor Bugbot for commit cf98919. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Render
data:URI images inChatMarkdownCHAT_MARKDOWN_SANITIZE_SCHEMAto permit thedata:protocol for imagesrcattributesINLINE_DATA_IMAGE_PATTERNand updatesmarkdownUrlTransformto pass recognizedimage/data URLs and Windows drive paths through unchanged, while non-image data URIs fall back to the unavailable imagesrcattributes withimage/data URIs now render directly instead of undergoing workspace-file URI rewritingMacroscope summarized cf98919.
Before / After
Before (release build): every non-HTTP embedding method renders a terminal
Image unavailableplaceholder.After (patched build): the same assistant response renders the images inline. Data URI embeds render identically to the path-based methods shown.