Skip to content

Quadratic DoS in parse_link_text via unmatched bracket runs

Moderate
lepture published GHSA-f32h-38gf-rg5r Jun 21, 2026

Package

pip mistune (pip)

Affected versions

3.2.0 + 3.2.1 and current main

Patched versions

3.3.0

Description

Summary

Feeding mistune.html() a string of unbalanced square brackets makes the call run in quadratic time. About 25 KB of brackets stalls a worker past 15 seconds on a Mac M2. 50 KB drags it out to roughly two minutes. Any server-side caller of mistune.html() on markdown an attacker can influence can be wedged.

Details

The payload is [ times N, then a single x, then ] times N. Every [ opens a parse_link attempt. parse_link calls parse_link_text in helpers.py, which forward-scans the rest of the source balancing brackets. The text ends up not being a link (no (url) after the closing bracket), the outer inline loop bumps the cursor by one character, and the next [ does the whole scan again. N full scans of an N-character input. Profile on N=1600 shows parse_link_text called 1599 times with about 2.56 million re.Pattern.search calls underneath, which is N² right on the money.

Tested on 3.2.0, then 3.2.1, then main HEAD. Identical on all three. The 3.2.1 release notes don't touch parse_link_text.

This isn't GHSA-hjph-f4mc-wx4c / CVE-2026-33441 from the May batch. That one's parse_link_title reached via malformed [label]: reference definitions with escaped brackets.

Suggested fix: cap how far parse_link_text scans forward. The existing LINK_LABEL = r"(?:[^\\\[\]]|\.){0,500}" already does this kind of thing. Optimising failed start positions for a given source would also work but the cap is the one-line option and matches code already in the file.

PoC

pip install mistune==3.2.1

import mistune, time
for n in (400, 800, 1600, 3200, 6400, 12800):
      md = '[' * n + 'x' + ']' * n
      t = time.perf_counter()
      mistune.html(md)
      print(n, len(md), f'{(time.perf_counter()-t)*1000:.0f} ms')

Output, Python 3.14, mistune 3.2.1:

400 801 35 ms
800 1601 130 ms
1600 3201 501 ms
3200 6401 2003 ms
6400 12801 8066 ms
12800 25601 killed at >15000 ms

Doubling N quadruples the time.

Impact

Denial of service. CWE-407 inefficient algorithmic complexity.

Anyone calling mistune.html() on input an attacker can influence. Web forms, comment fields, federated content, scheduled jobs pulling markdown from an external feed. Our own use is a Celery task rendering markdown from a first-party source so direct exposure for us is low, but the bug class hits every downstream putting user-facing markdown through mistune.

Severity

Moderate

CVE ID

No known CVE

Weaknesses

Inefficient Algorithmic Complexity

An algorithm in a product has an inefficient worst-case computational complexity that may be detrimental to system performance and can be triggered by an attacker, typically using crafted manipulations that ensure that the worst case is being reached. Learn more on MITRE.