Advisory Database
  • Advisories
  • Dependency Scanning
  1. npm
  2. ›
  3. @nuxtjs/mdc
  4. ›
  5. CVE-2026-63671

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

September 16, 2026

@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:

  1. SVG anchor xlink:href. validateProp only scheme-checks attributes named exactly href or src:
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.

  1. <iframe src="data:text/html,...">. data:text/html is present in unsafeLinkPrefix, but the check compares it against url.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 →

Affected versions

All versions before 0.22.1

Fixed versions

  • 0.22.1

Solution

Upgrade to version 0.22.1 or above.

Impact 8.1 HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N

Learn more about CVSS

Weakness

  • CWE-184: Incomplete List of Disallowed Inputs
  • CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')

Source file

npm/@nuxtjs/mdc/CVE-2026-63671.yml

Spotted a mistake? Edit the file on GitLab.

  • Site Repo
  • About GitLab
  • Terms
  • Privacy Statement
  • Contact

Page generated Tue, 22 Sep 2026 12:19:45 +0000.