fix: serialize images the parser would refuse as json:object fences - #3265
Conversation
`DefaultImageRenderer` emitted `` for any string `src`, but the parse side runs markdown-it's default `validateLink`, which rejects `javascript:`/`vbscript:`/`file:` protocols and every `data:` URI outside `image/(gif|png|jpeg|webp)`, an XSS guard that notably excludes `data:image/svg+xml`. A stored image with such a `src` therefore serialized to markdown its own reparse refuses: the token never forms, the image degrades to literal text, and in the edit loop the type change refuses the whole origin trace and regenerates every key in the document. A self-destroying serialization, keyed on the value rather than the schema. The renderer's shape check now also validates `src` with the parser's own validator, one module-level `new markdownit().validateLink` reference (the parse side never overrides it, so this mirrors exactly what the reparse will accept, with no duplicated regexes to drift), and a refused `src` falls back to the `json:object` form like any other shape failure, which reparses to the identical image, `_key` included. Pinned red-first: SVG data URI and `javascript:` srcs to the fence at block position and the tagged code span inline, an accepted PNG data URI keeping its markdown form, and the fence round-tripping to the identical value. The link annotation's `href` needs no matching guard: `DefaultLinkRenderer`'s own allowlist (`http`/`https`/`mailto`/`tel`) is a strict subset of what `validateLink` accepts, so a parser-refusable link is unemittable; probed, not just reasoned.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🦋 Changeset detectedLatest commit: 9555856 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Bundle Stats✅ No significant changes. All scenario measurements (7)🗺️
Significant means at least 1.0 KB and 1% gzip, or at least 5 ms and 10% import time. |
A stored image whose
srcthe markdown parser refuses no longer serializes to markdown that destroys it. Affected srcs:data:URIs outsideimage/(gif|png|jpeg|webp), notablydata:image/svg+xml, and script-ish protocols (javascript:,vbscript:,file:). Such images now serialize as ajson:objectfence (tagged code span inline) that reparses to the identical image,_keyincluded; accepted srcs keep their\form unchanged.The asymmetry this closes: the parse side runs markdown-it's default
validateLink(an XSS guard), so\never forms an image token, it parses as literal text. A stored SVG-data-URI image therefore round-tripped into escaped text, and in the edit loop the type change refused the whole origin trace and churned every key in the document, the field report that surfaced this. The guard uses the parser's own validator (one module-levelvalidateLinkreference, and the parse side never overrides it), so there are no duplicated regexes to drift.Pinned red-first: SVG data URI and
javascript:srcs to the fence at block position and the code span inline, an accepted PNG data URI keeping its markdown form, and the fence round-tripping to the identical value. Probed and needing no fix: the link annotation'shrefcannot hit the same trap,DefaultLinkRenderer's protocol allowlist is a strict subset of whatvalidateLinkaccepts. One corner is inherent and documented on the tracking ticket instead: an SVG data-URI image typed into markdown still becomes plain text silently, markdown-it swallows the token before degradation reporting can see an image.Note
Low Risk
Localized serializer change for image
srcvalidation with round-trip tests; normal image URLs and accepted data URIs are unaffected.Overview
DefaultImageRenderernow rejects imagesrcvalues that markdown-it's defaultvalidateLinkwould block (e.g.javascript:/vbscript:/file:, anddata:URIs other than png/gif/jpeg/webp). Those images serialize asjson:objectfences (block) or tagged code spans (inline) via the existingunknownTypepath instead of, so PT→MD→PT preserves the image object instead of turning it into literal text.Accepted
srcvalues are unchanged. The guard reuses a module-levelmarkdown-itvalidateLinkreference aligned with the parser. README and a changeset document the behavior; tests cover SVG/javascript:fallbacks, PNG data URIs, inline cases, and round-trip.Reviewed by Cursor Bugbot for commit 9555856. Bugbot is set up for automated code reviews on this repo. Configure here.