VYPR
Critical severity9.3NVD Advisory· Published Feb 6, 2025· Updated Apr 15, 2026

CVE-2025-24981

CVE-2025-24981

Description

MDC is a tool to take regular Markdown and write documents interacting deeply with a Vue component. In affected versions unsafe parsing logic of the URL from markdown can lead to arbitrary JavaScript code due to a bypass to the existing guards around the javascript: protocol scheme in the URL. The parsing logic implement in props.ts maintains a deny-list approach to filtering potential malicious payload. It does so by matching protocol schemes like javascript: and others. These security guards can be bypassed by an adversarial that provides JavaScript URLs with HTML entities encoded via hex string. Users who consume this library and perform markdown parsing from unvalidated sources could result in rendering vulnerable XSS anchor links. This vulnerability has been addressed in version 0.13.3 and all users are advised to upgrade. There are no known workarounds for this vulnerability.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
@nuxtjs/mdcnpm
< 0.13.30.13.3

Patches

3
99097738b556

Merge commit from fork

https://github.com/nuxt-modules/mdcFarnabazFeb 6, 2025via ghsa
2 files changed · +47 2
  • src/runtime/parser/utils/props.ts+19 1 modified
    @@ -9,13 +9,31 @@ export const unsafeLinkPrefix = [
       'data:text/xml'
     ]
     
    +function isAnchorLinkAllowed(value: string) {
    +  const decodedUrl = decodeURIComponent(value)
    +  const urlSanitized = decodedUrl.replace(/&#x([0-9a-f]+);?/gi, '')
    +    .replace(/&#(\d+);?/g, '')
    +    .replace(/&[a-z]+;?/gi, '')
    +
    +  try {
    +    const url = new URL(urlSanitized)
    +    if (unsafeLinkPrefix.some(prefix => url.protocol.toLowerCase().startsWith(prefix))) {
    +      return false
    +    }
    +  } catch {
    +    return false
    +  }
    +
    +  return true
    +}
    +
     export const validateProp = (attribute: string, value: string) => {
       if (attribute.startsWith('on')) {
         return false
       }
     
       if (attribute === 'href' || attribute === 'src') {
    -    return !unsafeLinkPrefix.some(prefix => value.toLowerCase().startsWith(prefix))
    +    return isAnchorLinkAllowed(value)
       }
     
       return true
    
  • test/markdown/xss.test.ts+28 1 modified
    @@ -10,6 +10,7 @@ const md = `\
     [XSS](vbscript:alert(document.domain))
     <javascript:prompt(document.cookie)>
     [x](y '<style>')
    +<a href="jav&#x09;ascript:alert('XSS');">Click Me</a>
     
     <!-- image -->
     
    @@ -31,7 +32,7 @@ const md = `\
     
     `.trim()
     
    -it('XSS', async () => {
    +it('XSS generic payloads', async () => {
       const { data, body } = await parseMarkdown(md)
     
       expect(Object.keys(data)).toHaveLength(2)
    @@ -41,3 +42,29 @@ it('XSS', async () => {
         expect(Object.entries(props as Record<string, any>).every(([k, v]) => validateProp(k, v))).toBeTruthy()
       }
     })
    +
    +it('XSS payloads with HTML entities should be caught', async () => {
    +  const md = `\
    +## XSS payloads with HTML entities
    +<a href="jav&#x09;ascript:alert('XSS');">Click Me 1</a>
    +<a href="jav&#x0A;ascript:alert('XSS');">Click Me 2</a>  
    +<a href="jav&#10;ascript:alert('XSS');">Click Me 3</a>
    +  
    +
    +`.trim()
    +
    +  // set the number of assertions to expect
    +  expect.assertions(4)
    +
    +  const { data, body } = await parseMarkdown(md)
    +
    +  expect(Object.keys(data)).toHaveLength(2)
    +
    +  for (const node of (body.children[1] as MDCElement).children) {
    +    const props = (node as MDCElement).props || {}
    +
    +    if ((node as MDCElement).tag === 'a') {
    +      expect(Object.keys(props)).toHaveLength(0)
    +    }
    +  }
    +})
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.