CVE-2026-63671: @nuxtjs/mdc's URL sanitizer misses SVG xlink:href and data:text/html, allowing XSS from untrusted markdown at the default configuration
@nuxtjs/mdc renders untrusted markdown (including raw HTML) to a Vue component tree. Across two prior advisories it added a URL/attribute sanitizer to block dangerous links in that HTML: validateProps / validateProp and an unsafeLinkPrefix deny-list (dist/runtime/parser/utils/props.js). The sanitizer runs at parse time (dist/runtime/parser/compiler.js) and parseMarkdown enables raw HTML by default (allowDangerousHtml: true, dist/runtime/parser/options.js), so the sanitizer is the only barrier and it applies with no configuration required.
Two sibling vectors bypass that sanitizer at the default configuration:
- SVG anchor
xlink:href.validateProponly scheme-checks attributes named exactlyhreforsrc:
if (attribute === "href" || attribute === "src") return isAnchorLinkAllowed(value);
return true;
An xlink:href (parsed to the hast property xLinkHref) is neither, so a javascript: URL on an SVG <a> is passed through. The renderer maps the property back to the real attribute (MDCRenderer.vue: find(html, "xLinkHref").attribute is xlink:href), so the output element is <a xlink:href="javascript:...">. Clicking it runs the script in the page origin. Plain <a href="javascript:..."> is correctly stripped, which is what makes this the un-patched sibling.
<iframe src="data:text/html,...">.data:text/htmlis present inunsafeLinkPrefix, but the check compares it againsturl.protocol:
if (unsafeLinkPrefix.some((prefix) => url.protocol.toLowerCase().startsWith(prefix))) return false;
For any data URI url.protocol is just "data:", so "data:".startsWith("data:text/html") is always false. Every data:text/* entry in the deny-list is therefore dead code, and <iframe src="data:text/html,<script>...</script>"> is allowed (iframe is not in the render-time dangerousTags, which is only ["script","base"]). The framed document executes script in an opaque origin. For contrast, srcdoc and object are blocked, so this is a precise gap rather than a general absence of filtering.
References
- github.com/advisories/GHSA-mxm6-v9r6-r94c
- github.com/nuxt-content/mdc/commit/61d636c2983f021288e4fc5c4006733b38cf0d53
- github.com/nuxt-content/mdc/pull/491
- github.com/nuxt-content/mdc/releases/tag/v0.22.1
- github.com/nuxt-content/mdc/security/advisories/GHSA-mxm6-v9r6-r94c
- nvd.nist.gov/vuln/detail/CVE-2026-63671
Code Behaviors & Features
Detect and mitigate CVE-2026-63671 with GitLab Dependency Scanning
Secure your software supply chain by verifying that all open source dependencies used in your projects contain no disclosed vulnerabilities. Learn more about Dependency Scanning →