# @nuxtjs/mdc's URL sanitizer misses SVG xlink:href and data:text/html, allowing XSS from untrusted markdown at the default configuration

@nuxtjs/mdc's URL sanitizer only scheme-checks href/src, so SVG xlink:href javascript: links and data:text/html iframes bypass it, executing XSS from untrusted markdown.

- Payout: Research
- Severity: high
- Program: @nuxtjs/mdc
- Found by: rz1027
- Disclosed: 2026-09-16
- CVE: CVE-2026-63671
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-mxm6-v9r6-r94c
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-mxm6-v9r6-r94c
- Tags: area:web domain:web impact:integrity kind:research platform:ghsa sev:high tech:nodejs technique:incomplete-fix technique:source-review vuln:misconfiguration vuln:xss

**Target:** Markdown-to-Vue parser/renderer (parseMarkdown, MDCRenderer)
**Root cause:** validateProp only scheme-checks attributes named exactly href/src, missing xlink:href (xLinkHref); and isAnchorLinkAllowed compares deny-list prefixes like data:text/html against url.protocol which is only 'data:', making those entries dead code.
**Steps:**
1. Parse untrusted markdown with raw HTML at default config: `parseMarkdown` with `allowDangerousHtml: true`.
2. Payload 1: `<a xlink:href="javascript:alert(1)">` inside SVG — parsed tree retains `a { xLinkHref: "javascript:..." }`; renderer maps to `xlink:href`, click executes script in page origin.
3. Payload 2: `<iframe src="data:text/html,<script>...</script>">` — `url.protocol` is `data:`, so `"data:".startsWith("data:text/html")` is false; iframe not in dangerousTags `["script","base"]`, so it loads and executes in opaque origin.
4. Control: plain `href="javascript:..."` and `srcdoc=...` are stripped, confirming the gap is specific.
5. Run `sh poc/poc.sh` to install mdc and serve poc.html over http; click SVG link and observe iframe firing, page prints VULNERABLE.
**How found:** Noticed prior advisories added a sanitizer for href/src; observed validateProp only checks attributes named exactly href or src, so the SVG sibling attribute xlink:href (hast xLinkHref) is unchecked. Separately noticed data:text/html in unsafeLinkPrefix is compared against url.protocol, which for data URIs is only 'data:', making the entry dead code; confirmed iframe absent from dangerousTags.
**Exploitation:** Attacker supplies untrusted markdown containing raw HTML with an SVG anchor using xlink:href=javascript: or an iframe with data:text/html src. When a victim views the rendered page and clicks the SVG link (or the iframe loads), script executes in the page origin (or opaque origin for the iframe), enabling session/data theft.
**Insight:** When a sanitizer scheme-checks attribute names, enumerate every alias the renderer maps back to a URL-bearing attribute (SVG xlink:href, xLinkHref, formaction, etc.). Also, deny-list entries containing a MIME type can never match url.protocol — check the full URL string, not the parsed protocol.

