CVE-2026-59928: Mistune block_parser: quadratic-time parsing on long lists of repeated reference-link definitions
Summary
Type: Algorithmic-complexity DoS in reference-link definition handling. A markdown document with N reference-link definitions of the same key (or many distinct keys) takes O(N²) parser time. 5000 repeated [a]: u\n definitions take ~1.1 second; 10000 → ~4.5 seconds. File: src/mistune/blockparser.py (reference-link def parsing) and the surrounding reflinks env-dictionary handling. Root cause: every reference definition is parsed by scanning forward from each candidate position. The unikey normalisation runs per-def, the dictionary insert is per-def, and the lookup-by-label-then-iterate-defs path is linear in the number of stored defs. For input with N defs, the total work is O(N²).
Affected Code
src/mistune/blockparser.py — reference-definition rule fires on every line that matches [label]: url. For each one: - unikey(label) is called (linear scan of the label). - The def is appended to state.env['reflinks']. - Later inline-link resolution looks up by unikey(label) in the dict (O(1)) but the surrounding parser revisits the def list for paragraph-vs-def disambiguation.
The cumulative parse time grows as the square of the number of defs.
Why it's wrong: the parser does not amortise the def-list scan. A single forward pass with a hash-keyed dict (already in place) plus a per-line classifier should make this O(N).
Exploit Chain
1. Application uses mistune to render attacker-supplied markdown. No plugins required. 2. Attacker submits a 35 KB document of [a]: u\n repeated 5000 times followed by [click][a]. 3. CPU pegs for ~1.1 seconds. 10000 defs → ~4.5 s. 20000 → ~18 s. Doubling input quadruples time.
Security Impact
Attacker capability: small input → large CPU. Predictable scaling. Can be repeated. Preconditions: application uses mistune.createmarkdown() (default config) on attacker-supplied markdown. Worth noting: the reflinks dictionary persists for the lifetime of the parse, so a long document with many defs builds up memory; with N defs of attacker-chosen length, the per-def normalisation cost compounds. Differential: PoC-verified against mistune@3.2.1, default config:
python import mistune, time md = mistune.createmarkdown() for n in [1000, 2000, 5000, 10000]: s = '[a]: u\n' n + '[click][a]' t = time.time() md(s) print(f' ref defs {n} ({len(s)}b): {(time.time() - t) 1000:.0f}ms')
Output (Python 3.13, Linux, 2.5GHz CPU): ref defs 1000 ( 7012b): 46ms ref defs 2000 (14012b): 186ms ref defs 5000 (35012b): 1121ms ref defs 10000 (70012b): 4400ms
The patched build (with the surrounding parser amortised to O(N)) keeps the time linear.
Suggested Fix
Replace the per-def re-scan with a single forward pass that classifies each line into refdef | paragraph | other once and only inserts into reflinks once per def. The dict already exists; the wasted work is in the surrounding scan loop, not in the dict operations.
A regression test asserting that md('[a]: u\n' 50000 + '[click][a]') completes in under 1 second would catch any regression.
Other sources
Mistune is a Python Markdown parser with renderers and plugins. Prior to 3.3.0, a Markdown document containing many repeated or distinct reference-link definitions causes quadratic work in src/mistune/blockparser.py and the reflinks environment dictionary handling, allowing denial of service through CPU exhaustion. This issue is fixed in version 3.3.0.
— MITRE
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
pip/mistuneto a version that resolves this vulnerability.Fixed in 3.3.0 - Upgrade
Upgrade
mistuneto a version that resolves this vulnerability.Fixed in 3.3.0 - Compensating control
Apply a request size / CPU-time limit for attacker-supplied Markdown rendered with mistune (e.g., cap the maximum Markdown length and/or abort rendering when parsing exceeds a threshold), since large numbers of repeated reference-link definitions like '[a]: u\n' repeated 5000 times cause ~O(N^2) CPU exhaustion in mistune versions prior to 3.3.0.
Event History
Frequently Asked Questions
What is the severity of CVE-2026-59928?
CVE-2026-59928 has a severity rating of 7.5, which is classified as high.
How do I fix CVE-2026-59928?
To fix CVE-2026-59928, update Mistune to version 3.3.0 or later.
What kind of vulnerability is CVE-2026-59928?
CVE-2026-59928 is a denial of service vulnerability due to quadratic-time parsing in Mistune.
Which software is affected by CVE-2026-59928?
CVE-2026-59928 affects the Mistune Markdown parser prior to version 3.3.0.
What causes the issue in CVE-2026-59928?
The issue in CVE-2026-59928 is caused by many repeated reference-link definitions leading to inefficient parsing.