Repository navigation
chore(deps): update dependency markdown-it to v14.3.3 [security] - #1955
Open
renovate[bot] wants to merge 1 commit into
Open
renovate[bot] wants to merge 1 commit into
renovate[bot] wants to merge 1 commit into
Conversation
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR contains the following updates:
14.3.2→14.3.3markdown-it: Quadratic-time denial of service in inline HTML parsing with html enabled
CVE-2026-111766 / GHSA-vfgh-jcmw-g37q
More information
Details
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
commonmarkpreset enables it.The issue was reported against the published
markdown-it@15.0.2package on Node.js 20 and reproduced on the current source with Node.js 24.16.0.Details
src/rules_inline/text.tstreats<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.tsapplies an anchored regular expression to the remaining input:The comment, processing instruction, declaration, and CDATA alternatives in
src/common/html_re.tsscan 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
xkeeps 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 intest/markdown-it/pathological.test.mjsalready contains a reproducer: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:
Save the following as
poc.mjsand runnode poc.mjs:Measurements from the original report on
markdown-it@15.0.2, Node.js 20:An eightfold increase in repetitions produces approximately 35–60 times the execution time, consistent with quadratic growth becoming dominant.
For the comment payload at 64,000 repetitions:
The existing pathological-test payload with 100,000 comment openers took 33 ms with HTML disabled and 21,030 ms with HTML enabled. A separate comment payload with 128,000 repetitions, approximately 500 KiB, took 32,847 ms.
Exact timings depend on the runtime and hardware.
Impact
This is an availability issue affecting applications that render attacker-controlled Markdown with
html: true, including applications using thecommonmarkpreset.On Node.js, a synchronous
render()call can occupy a CPU core and block the event loop for seconds or tens of seconds, delaying other requests handled by the same process. Repeated submissions can cause denial of service. Browser applications can similarly become unresponsive when rendering on the main thread.Sanitizing the generated HTML afterwards does not prevent the issue because the expensive processing occurs during Markdown rendering.
The default configuration, with HTML disabled, is unaffected by these payloads. Disabling HTML or limiting input size can reduce exposure while a fix is prepared.
The reported affected release is
15.0.2; the full affected version range has not been established.Severity
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:LReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
markdown-it: Quadratic-time rendering of a single multi-line link reference definition with default options (regression since 14.0)
CVE-2026-111758 / GHSA-gfr2-rv44-r23c
More information
Details
Summary
A link reference definition whose label or title is never closed is O(n²) in markdown-it 15.0.2 with default options. Continuation lines are pulled lazily with str += lineContent in src/rules_block/reference.ts, and the subsequent charCodeAt and slice calls flatten the V8 cons-string, copying everything collected so far; this runs before the rule decides the definition is invalid. It is a regression introduced by PR #1004 in 14.0.0: 13.0.2 processed a 313 KB input in 125 ms, while every version since takes about 11 seconds on the same input. At the sizes below, 200 KB takes 3.6 seconds, 400 KB takes 18.1 seconds, and 800 KB takes 74.0 seconds, which is roughly 4–5× per doubling. No options are required to trigger it.
Details
src/rules_block/reference.ts appends continuation lines with str += lineContent at lines 74, 83, 100, 133, and 150, then keeps indexing the accumulated string via str.charCodeAt(pos) in the label and whitespace loops and str.slice(...) in parseLinkTitle. V8 represents += as a cons-string, and the next charCodeAt or slice flattens it, copying everything collected so far, so one definition spanning n lines costs O(n²). Isolation confirms the rule is responsible: block-only parsing with inline disabled is still quadratic, md.disable('reference') makes the same input linear, and the same text without the leading [ is linear. The fix is to track positions in state.src instead of building str, or to collect line slices in an array and parse across them. At minimum, stop scanning the label after 999 characters (CommonMark §6.3) before pulling more lines, and cap title continuation. Add a pathological test with a 100k-line unclosed title and label. Open PR #1215 edits the same file but its label check runs after the label loop, so it does not bound either variant and the fix can land together with that PR.
The observed output from PoC was:
unclosed title n=100000 200009 B 3585.5 ms
unclosed title n=200000 400009 B 18107.1 ms (5.05x)
unclosed title n=400000 800009 B 73954.4 ms (4.08x)
Regression comparison at 313 KB: 13.0.2 → 125 ms, 14.1.0 → 11.4 s, 15.0.0 → 10.6 s, 15.0.2 → 10.7 s.
Proof of concept
How to execute the PoC:
PoC below is:
Impact
This is an algorithmic-complexity denial of service (CWE-407). Any server that renders user Markdown with markdown-it is affected with default options, including comments, issues, chat, wikis, docs previews, and LLM chat UIs. A ~400 KB request body blocks the Node.js event loop for about 18 seconds and an ~800 KB body for about 74 seconds. This is the same class and attacker model as GHSA-253c, but it is reachable without any opt-in option, since the affected path is a core block rule.
Severity
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:HReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
Release Notes
markdown-it/markdown-it (markdown-it)
v14.3.3Compare Source
Configuration
📅 Schedule: (UTC)
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR was generated by Mend Renovate. View the repository job log.