CVE-2026-63671
Executive Summary
CVE-2026-63671 is a cross-site scripting (XSS) vulnerability in @nuxtjs/mdc, a Nuxt module that parses Markdown into documents rendered through a Vue component. Prior to version 0.22.1, the module invokes parseMarkdown with allowDangerousHtml enabled by default and relies on a set of internal validation helpers (validateProps, validateProp, unsafeLinkPrefix) to strip executable URLs from untrusted Markdown; two gaps in that sanitization logic allow javascript: and data:text/html payloads to survive and execute in a victim's browser. Any application that renders user-supplied or third-party Markdown through an affected version is impacted, with page-origin script execution enabling session theft, credential phishing, and full DOM manipulation, rated CVSS 8.1 (High). No public PoC, exploit code, or CISA KEV listing currently exists.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Technical Analysis
@nuxtjs/mdc converts Markdown into a structured document that is then rendered by a dedicated Vue component. To support legitimate inline HTML, the Markdown parser is initialized with allowDangerousHtml set to true by default. Because this setting permits raw HTML to pass through the parsing pipeline, the module depends on its own sanitization utilities — validateProps, validateProp, and unsafeLinkPrefix — to neutralize executable URL schemes in untrusted content. The vulnerability resides in exactly two shortcomings of that layer:
Attribute-name coverage gap (
xLinkHref).validatePropis documented as checking only attributes namedhreforsrc. SVG elements express link targets through thexlink:hrefattribute, which, when represented in the Markdown/property pipeline (and in Vue's attribute-casing conventions) asxLinkHref, does not match thehrefstring that the validator inspects. Ajavascript:URL supplied through this attribute therefore retains its scheme and executes in the page origin when the rendered element is selected (clicked/activated) by the victim.Protocol-comparison gap (
data:text/html). The denylist entries targetingdata:text/htmlare compared againsturl.protocol. The WHATWG URL parser reports the scheme of adata:text/html,...URL asdata:only — the media type is carried in the URL's path/body, never inprotocol. Consequently, aniframe srccontaining adata:text/htmldocument never matches the denylist entry and survives sanitization. When the iframe loads, the payload executes in an opaque origin (a unique, sandbox-like origin) rather than the page's own origin.
The NVD description explicitly notes that plain href javascript: URLs, srcdoc, object, script, and base elements are already blocked. This is significant for defenders: the vulnerable paths are not a wholesale bypass of the sanitizer but two narrowly scoped sibling gaps left open by an otherwise functional blocklist. That framing also explains the CVSS profile — the vector AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N indicates a network-reachable flaw requiring only user interaction (rendering or activating injected content), with high confidentiality and integrity impact but no scope change, consistent with script executing in the page origin or an opaque origin rather than crossing a security boundary into the host.
Attack surface is any Nuxt application that passes externally sourced Markdown (comments, CMS content, rendered READMEs, chat messages, documentation portals, user profiles) into @nuxtjs/mdc on a version below 0.22.1. Because the parser is configured with dangerous HTML enabled by default, no misconfiguration is required on the part of the integrator — the default posture is exploitable if the injected attribute or iframe path is reached. The patch version, 0.22.1, presumably tightens validateProp to cover xlink:href/xLinkHref and corrects the data:text/html denylist comparison so that the media type — not merely url.protocol — is evaluated; exact code changes are not available in the supplied NVD text and should be confirmed against the upstream diff.
The root-cause classification is CWE-79 (Improper Neutralization of Input During Web Page Generation), specifically a sanitizer allowlist/denylist coverage defect rather than a raw-output error. The integrity weakness here is characteristic of blocklist-based HTML sanitization: enumerating forbidden schemes and attribute names is fragile against attribute aliases and URL-component semantics.
Exploitation Scenarios
No public PoC is available for CVE-2026-63671; the attack chain below is inferred from the vulnerability class (stored/reflected DOM XSS via sanitizer bypass) and the exact bypass paths enumerated in the NVD description.
1) Reconnaissance / target identification. An attacker identifies a Nuxt application that accepts Markdown from a party the attacker can influence: an issue tracker, comment system, CMS field, chat channel, or any content feed rendered by the affected module. Version fingerprinting can be performed passively (e.g., Shodan dorks against http.html:"@nuxtjs/mdc" or Nuxt page markers) or by observing rendered behavior; the attacker's goal is to confirm that Markdown from their input source reaches the parseMarkdown pipeline on a version below 0.22.1.
2) Triggering the flaw class. The attacker submits Markdown containing one of the two surviving payload forms:
- An SVG link attribute expressed as
xLinkHrefcarrying ajavascript:URL. BecausevalidatePropfilters onlyhrefandsrc, this attribute escapes inspection, and the executable scheme is preserved through rendering. - An
iframewith asrcwhose value is adata:text/htmldocument. The denylist comparison againsturl.protocolsees onlydata:and therefore fails to match thedata:text/htmlentry, so the iframe survives.
Both submissions target the same vulnerability class — insufficient sanitization of untrusted HTML embedded in Markdown — and rely on payloads that the description confirms are not blocked (unlike srcdoc, object, script, base, and plain javascript: hrefs).
3) Payload/execution method (class level). The payload executes only when a victim interacts with the rendered content: in the xLinkHref case, activation of the rendered SVG link element causes the javascript: URL to be evaluated in the page origin; in the data:text/html case, loading the surviving iframe evaluates the embedded HTML in an opaque origin. The attacker supplies a script body of their choosing — standard XSS tradecraft such as exfiltrating session tokens or cookies accessible to the script context, harvesting keystrokes or form input, injecting a fraudulent login prompt, or silently performing authenticated actions as the victim.
4) Post-exploitation impact. Page-origin execution (the xLinkHref path) yields the most severe outcome: the attacker operates with the application's origin, reaching same-origin DOM state, readable cookies (where not HttpOnly), localStorage-resident tokens, and in-page APIs. The data:text/html iframe path, executing in an opaque origin, is more constrained but still enables arbitrary attacker-controlled content rendering, social-engineering and phishing at scale, and — depending on message-passing or opener relationships in the host application — further chained attacks. In both cases the CVSS vector's high integrity rating reflects the attacker's ability to manipulate what the victim sees and does within the reachable context.
Impact Assessment
CVSS 3.1 score: 8.1 (High), vector CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N.
- Attack Vector (N): Exploit is deliverable over the network via injected Markdown content.
- Attack Complexity (L): No special conditions or race states; the two known bypass paths are deterministic —
xLinkHrefanddata:text/htmliframesrcsimply do not match their respective filters. - Privileges Required (N): No authenticated access needed to craft the payload; only an input channel the attacker can influence.
- User Interaction (R): A victim must render the content and, for the
xLinkHrefpath, activate the element; the iframe path fires on load of the rendered document. - Scope (U): Impact remains within the vulnerable component's security context; the opaque-origin iframe behavior further reinforces that no scope crossing is credited.
- Confidentiality (H) / Integrity (H): Script execution in the page origin can read sensitive client-side material and rewrite the rendered page arbitrarily; both are rated High. Availability is rated None.
Blast radius: every Nuxt application consuming untrusted Markdown via @nuxtjs/mdc < 0.22.1. Because the module is used for documentation sites, CMS front ends, forums, and content platforms, a single injected payload can be persisted and served to every visitor of the affected page — making this a potential stored-XSS worm vector in multi-tenant or comment-enabled deployments. Enterprise risk concentrates in internal wikis/documentation portals (session theft leading to lateral movement) and customer-facing content sites (defacement, credential phishing, reputational and regulatory exposure). There is currently no evidence of exploit-in-the-wild, KEV listing, or threat-actor campaign.
Detection Guidance
Sigma Rule
title: MDC Markdown Sanitizer Bypass Attempts (xLinkHref / data:text/html iframe)
id: 8f1c4a92-3d7b-4e10-9c5a-6b2e7a44d1f3
status: experimental
description: Detects Markdown or HTML submitted to applications that contain known @nuxtjs/mdc < 0.22.1 sanitizer bypass payload patterns.
references:
- https://nvd.nist.gov/vuln/detail/CVE-2026-63671
author: valtersit.com
date: 2026-01-01
logsource:
category: application
product: nuxt
detection:
selection_xlink:
body|contains|all:
- 'xLinkHref'
- 'javascript:'
selection_dataiframe:
body|contains|all:
- '<iframe'
- 'data:text/html'
condition: selection_xlink or selection_dataiframe
fields:
- src_ip
- user_agent
- uri
- body
falsepositives:
- Security research and scanner traffic
- Legitimate documentation describing these bypass classes
level: high
tags:
- attack.t1189
- cwe.79
YARA Rule
rule CVE_2026_63671_MDC_Sanitizer_Bypass
{
meta:
author = "valtersit.com"
description = "Detects @nuxtjs/mdc < 0.22.1 XSS sanitizer bypass payloads in Markdown/HTML/packaged content"
reference = "https://nvd.nist.gov/vuln/detail/CVE-2026-63671"
cve = "CVE-2026-63671"
date = "2026-01-01"
strings:
$xlink_js = /xLinkHref\s*=\s*["']?\s*javascript:/ nocase
$xlink_xml = /xlink:href\s*=\s*["']?\s*javascript:/ nocase
$dataiframe = /<iframe[^>]{0,300}src\s*=\s*["']?\s*data:text\/html/ nocase
$mdc_pkg = "@nuxtjs/mdc" nocase
condition:
(uint16(0) != 0x5A4D and ($xlink_js or $xlink_xml or $dataiframe)) or
($mdc_pkg and ($xlink_js or $dataiframe))
}
Suricata IDS Rule
alert http any any -> any any (msg:"CVE-2026-63671 @nuxtjs/mdc sanitizer bypass - xLinkHref javascript URL"; flow:established,to_server; http.method; content:"POST"; http.request_body; content:"xLinkHref"; nocase; http.request_body; content:"javascript:"; nocase; distance:0; within:200; classtype:web-application-attack; reference:cve,2026-63671; reference:url,nvd.nist.gov/vuln/detail/CVE-2026-63671; sid:202663671; rev:1;)
alert http any any -> any any (msg:"CVE-2026-63671 @nuxtjs/mdc sanitizer bypass - data:text/html iframe"; flow:established,to_server; http.method; content:"POST"; http.request_body; content:"<iframe"; nocase; http.request_body; content:"data:text/html"; nocase; distance:0; within:300; classtype:web-application-attack; reference:cve,2026-63671; reference:url,nvd.nist.gov/vuln/detail/CVE-2026-63671; sid:202663672; rev:1;)
Elastic Detection
sequence by process.entity_id
[process where event.type == "start" and
process.command_line : ("*xLinkHref*" or "*data:text/html*")]
[network where event.type == "start" and
network.direction == "outbound" and
not cidr_match(destination.ip, "10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16")]
process where event.type == "start" and
process.command_line : "*@nuxtjs/mdc*" and
process.command_line : ("*xLinkHref*" or "*data:text/html*" or "*allowDangerousHtml*")
Splunk SPL Query
index=web sourcetype=access_combined OR sourcetype=nuxt_app
| eval raw = coalesce(uri, url, request_body, _raw)
| where match(raw, "(?i)xLinkHref[^>]{0,50}javascript:")
OR match(raw, "(?i)<iframe[^>]{0,300}src\s*=\s*['\"]?\s*data:text/html")
| stats count min(_time) as first_seen max(_time) as last_seen
values(src_ip) as sources values(uri) as uris by user_agent, host
| where count > 0
| convert ctime(first_seen) ctime(last_seen)
| sort - count
Wazuh OSSEC Rule
<group name="web,appsec,mdc,cve-2026-63671">
<rule id="2026631" level="12" frequency="1" timeframe="300">
<if_sid>31100</if_sid>
<match>xLinkHref</match>
<match>javascript:</match>
<description>CVE-2026-63671: @nuxtjs/mdc xLinkHref javascript: sanitizer bypass attempt</description>
<mitre>
<id>T1189</id>
</mitre>
<group>cve_2026_63671,xss,</group>
</rule>
<rule id="2026632" level="12" frequency="1" timeframe="300">
<if_sid>31100</if_sid>
<match>data:text/html</match>
<match>iframe</match>
<description>CVE-2026-63671: @nuxtjs/mdc data:text/html iframe sanitizer bypass attempt</description>
<mitre>
<id>T1189</id>
</mitre>
<group>cve_2026_63671,xss,</group>
</rule>
</group>
Mitigation & Patch Guidance
Patch confidence: 0/4 (UNPATCHED — no patch evidence from any tracked source). The NVD description states the issue is fixed in version 0.22.1, but no vendor advisory, commit, or tracked patch source is available for confirmation. Treat all environments below 0.22.1 as vulnerable until an independently verified build is deployed.
1) Immediate mitigations (apply before patching is possible):
- Upgrade
@nuxtjs/mdcto 0.22.1 or later as the primary remediation. This is the only fix identified in the vulnerability disclosure and should be prioritized despite low patch confidence, since the NVD text explicitly identifies 0.22.1 as the fixed release. - If upgrade is not immediately possible, disable raw HTML handling in the parser configuration (i.e., do not rely on
allowDangerousHtmlbeing enabled for untrusted content) and/or pre-sanitize all Markdown input with a maintained, well-audited sanitizer before it reaches the module. - Treat all externally sourced Markdown as untrusted: gate who can submit Markdown into rendered surfaces (comments, profiles, CMS fields), and audit existing stored content for
<iframe,data:text/html,xlink:href, andxLinkHrefpatterns. - Deploy a strict Content-Security-Policy as defense-in-depth: disallow
data:inframe-src/child-srcandjavascript:inscript-src, and avoidunsafe-inline. CSP does not fix the sanitizer but materially reduces payload effectiveness. - Mark session cookies
HttpOnlyandSecure, and useSameSiterestrictions, to limit token theft via page-origin script execution.
2) Patch/upgrade steps:
- Pin
@nuxtjs/mdc@>=0.22.1inpackage.json(or the equivalent lockfile entry) and rebuild/redeploy all Nuxt applications using the module. - Verify the resolved version in your build artifacts (
npm ls @nuxtjs/mdcor lockfile inspection) — transitive dependency resolution can silently retain an older copy. - Where the module is bundled into a container image or static build, rebuild the image and purge CDN caches to ensure no stale vulnerable bundle remains served.
- Because patch confidence is 0/4, independently validate the fix: confirm that
xLinkHrefcarryingjavascript:and an iframe withdata:text/htmlsrcare both neutralized in a staging render test before closing the finding.
3) Long-term hardening:
- Replace blocklist-based sanitization assumptions with an allowlist-first rendering pipeline (e.g., a maintained HTML sanitizer) for any content crossing a trust boundary; the two bypasses here are textbook blocklist failures (attribute alias and URL-component semantics).
- Adopt SCA/SCA-in-CI gates that alert on Markdown/HTML sanitizer advisories and enforce vulnerability-free dependency versions at build time.
- Instrument the supplied Sigma/Suricata/Wazuh detections and monitor for repeated sanitizer-bypass attempts, which indicate active probing even before an exploit is public.
- Add regression tests for sanitizer behavior covering attribute aliases (
xlink:href/xLinkHref) and protocol/media-type comparisons (data:text/htmlvsurl.protocol) to catch future sibling gaps.
References
- NVD — CVE-2026-63671: https://nvd.nist.gov/vuln/detail/CVE-2026-63671
- CWE-79 — Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting'): https://cwe.mitre.org/data/definitions/79.html
- MITRE ATT&CK T1189 — Drive-by Compromise: https://attack.mitre.org/techniques/T1189/
- @nuxtjs/mdc module (Nuxt) — upstream project and release history: https://github.com/nuxt-modules/mdc
- CVSS 3.1 Specification (Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N): https://www.first.org/cvss/v3.1/specification-document
Threat actor / exploit-in-the-wild evidence: None available. There is no public PoC, no Nuclei template, no published exploit code, no CISA KEV listing, and no known campaign attributed to CVE-2026-63671 at the time of writing. EPSS has not yet been scored by FIRST.org; no EPSS value is reported here.
💣 PoC CODE AVAILABLE
Exploit code for this CVE is tracked in our database.
Access poc_code via API Pro.