CVE-2026-59922
Mistune plugins/formatting: quadratic-time parsing on long runs of `~~x~~`, `==x==`, and `^^x^^` markers (strikethrough / mark / insert)
Mistune is a Python Markdown parser with renderers and plugins. Prior to 3.3.0, a run of closed tilde, equals-sign, or caret marker pairs around a character causes quadratic work in src/mistune/plugins/formatting.py when the strikethrough, mark, or insert plugin scans for matching markers from each possible start position, allowing denial of service through CPU exhaustion. This issue is fixed in version 3.3.0.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- None
- Integrity
- None
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
7.5
Mistune plugins/formatting: quadratic-time parsing on long runs of `~~x~~`, `==x==`, and `^^x^^` markers (strikethrough / mark / insert)
Mistune is a Python Markdown parser with renderers and plugins. Prior to 3.3.0, a run of closed tilde, equals-sign, or caret marker pairs around a character causes quadratic work in src/mistune/plugins/formatting.py when the strikethrough, mark, or insert plugin scans for matching markers from each possible start position, allowing denial of service through CPU exhaustion. This issue is fixed in version 3.3.0.
- Record
CVE-2026-59922- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-407, CWE-1333
- Updated
- 2026-11-02
EUVDEUVD-2026-42329
7.5
Mistune is a Python Markdown parser with renderers and plugins. Prior to 3.3.0, a run of closed tilde, equals-sign, or caret marker pairs around a character causes quadratic work in src/mistune/plugins/formatting.py when the strikethrough, mark, or insert plugin scans for matching markers from each possible start position, allowing denial of service through CPU exhaustion. This issue is fixed in version 3.3.0.
- Record
EUVD-2026-42329- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-c8j7-8cv4-2xmq
7.5
Mistune plugins/formatting: quadratic-time parsing on long runs of `~~x~~`, `==x==`, and `^^x^^` markers (strikethrough / mark / insert)
Summary
Type: Algorithmic-complexity denial of service. A run of N closed pairs ~~x~~~~x~~... (or the analogous ==x== for mark, ^^x^^ for insert) causes O(N²) work in the formatting parser. With the strikethrough, mark, or insert plugin enabled, an 8 KB input pegs the CPU for ~4 seconds; 16 KB → ~17 seconds.
File: src/mistune/plugins/formatting.py, lines 13-15 (the _STRIKE_END / _MARK_END / _INSERT_END patterns and their per-position scan).
Root cause: for each opening ~~/==/^^ the parser scans forward for the matching close pattern. The scan itself uses a bounded regex, but the parser tries the close-scan at every potential start position. For input shaped like ~~x~~ repeated N times, every ~~ is examined as a possible start, each scan covers up to the end of input. Total work is O(N²). Default config without these plugins handles the same input in linear time (4 ms for 4000 reps), confirming the cost is in the formatting plugin's per-marker scan, not in core parsing.
Affected Code
File: src/mistune/plugins/formatting.py, lines 12-16.
_STRIKE_END = re.compile(r"(?:" + PREVENT_BACKSLASH + r"\\~|[^\s~])~~(?!~)")
_MARK_END = re.compile(r"(?:" + PREVENT_BACKSLASH + r"\\=|[^\s=])==(?!=)")
_INSERT_END = re.compile(r"(?:" + PREVENT_BACKSLASH + r"\\\^|[^\s^])\^\^(?!\^)")
# Each pattern is scanned forward from every start position fired by the
# corresponding inline rule. The end-pattern itself is bounded; the cost
# comes from the surrounding parser invoking the scan at every '~~' / '==' / '^^'
# token in the input, giving N starts × O(N) per scan = O(N^2) total.
Why it's wrong: the same algorithmic-complexity flaw class as [ / [a parsing in core: a per-token retry loop without memoisation of failed positions. Each formatting marker is tried as both a potential start and as a continuation. A linear-pass delimiter-stack algorithm (matching how commonmark-py and markdown-it-py handle emphasis) would do this work in O(N) total. The bounded regex on each individual scan does not bound the parser-level repetition.
Exploit Chain
- Application uses mistune to render user-supplied markdown and has any of the formatting plugins enabled (
plugins=['strikethrough'],['mark'],['insert'], or any superset). These plugins are commonly enabled because GitHub-flavoured-Markdown compatibility requires~~strikethrough~~and many editors emit==highlighting==and^^underline^^shortcuts. - Attacker submits an 8 KB markdown payload of the form
~~x~~~~x~~~~x~~...(40 000 characters of~~x~~repeated 8000 times, or the analogous shape with==/^^). - Server calls
mistune.create_markdown(plugins=['strikethrough'])(payload). CPU pegs for ~4 seconds; 16 KB → ~17 seconds; 32 KB → ~70 seconds. Pure CPU cost, no significant memory growth. - Repeating the request floods the worker pool. On a single-thread WSGI handler this is one request per outage; on a thread pool, a small number of concurrent attackers exhausts capacity.
Security Impact
Severity: sec-high. Network-reachable, no authentication, predictable scaling, single-payload primitive. Only requires a user-supplied markdown sink and a formatting plugin enabled — both are common.
Attacker capability: small input → large CPU. Doubling input size quadruples CPU time. Sustained requests deny service to other users.
Preconditions: application uses mistune with any of strikethrough, mark, or insert plugins enabled. Default config does NOT enable these (so the attack only fires against the substantial deployed population that turns them on for GFM/markdown-extra compatibility).
Differential: PoC-verified against [email protected]:
import mistune, time
md = mistune.create_markdown(plugins=['strikethrough'])
for n in [500, 1000, 2000, 4000, 8000]:
s = '~~x~~' * n
t = time.time()
md(s)
print(f' ~~x~~ * {n} ({len(s)}b): {(time.time()…
- Record
GHSA-c8j7-8cv4-2xmq- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-407, CWE-1333
- Updated
- 2026-11-02
NVD
7.5
Mistune is a Python Markdown parser with renderers and plugins. Prior to 3.3.0, a run of closed tilde, equals-sign, or caret marker pairs around a character causes quadratic work in src/mistune/plugins/formatting.py when the strikethrough, mark, or insert plugin scans for matching markers from each possible start position, allowing denial of service through CPU exhaustion. This issue is fixed in version 3.3.0.
- Record
CVE-2026-59922- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-407, CWE-1333
- Updated
- 2026-11-02
OSV
7.5
Mistune plugins/formatting: quadratic-time parsing on long runs of `~~x~~`, `==x==`, and `^^x^^` markers (strikethrough / mark / insert)
Mistune is a Python Markdown parser with renderers and plugins. Prior to 3.3.0, a run of closed tilde, equals-sign, or caret marker pairs around a character causes quadratic work in src/mistune/plugins/formatting.py when the strikethrough, mark, or insert plugin scans for matching markers from each possible start position, allowing denial of service through CPU exhaustion. This issue is fixed in version 3.3.0.
- Record
CVE-2026-59922- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-1333, CWE-407
- Updated
- 2026-11-02
OSVDEBIAN-CVE-2026-59922
7.5
Mistune is a Python Markdown parser with renderers and plugins. Prior to 3.3.0, a run of closed tilde, equals-sign, or caret marker pairs around a character causes quadratic work in src/mistune/plugins/formatting.py when the strikethrough, mark, or insert plugin scans for matching markers from each possible start position, allowing denial of service through CPU exhaustion. This issue is fixed in version 3.3.0.
- Record
DEBIAN-CVE-2026-59922- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Updated
- 2026-11-02
Show 6 moreShow less
OSVGHSA-c8j7-8cv4-2xmq
7.5
Mistune plugins/formatting: quadratic-time parsing on long runs of `~~x~~`, `==x==`, and `^^x^^` markers (strikethrough / mark / insert)
Summary
Type: Algorithmic-complexity denial of service. A run of N closed pairs ~~x~~~~x~~... (or the analogous ==x== for mark, ^^x^^ for insert) causes O(N²) work in the formatting parser. With the strikethrough, mark, or insert plugin enabled, an 8 KB input pegs the CPU for ~4 seconds; 16 KB → ~17 seconds.
File: src/mistune/plugins/formatting.py, lines 13-15 (the _STRIKE_END / _MARK_END / _INSERT_END patterns and their per-position scan).
Root cause: for each opening ~~/==/^^ the parser scans forward for the matching close pattern. The scan itself uses a bounded regex, but the parser tries the close-scan at every potential start position. For input shaped like ~~x~~ repeated N times, every ~~ is examined as a possible start, each scan covers up to the end of input. Total work is O(N²). Default config without these plugins handles the same input in linear time (4 ms for 4000 reps), confirming the cost is in the formatting plugin's per-marker scan, not in core parsing.
Affected Code
File: src/mistune/plugins/formatting.py, lines 12-16.
_STRIKE_END = re.compile(r"(?:" + PREVENT_BACKSLASH + r"\\~|[^\s~])~~(?!~)")
_MARK_END = re.compile(r"(?:" + PREVENT_BACKSLASH + r"\\=|[^\s=])==(?!=)")
_INSERT_END = re.compile(r"(?:" + PREVENT_BACKSLASH + r"\\\^|[^\s^])\^\^(?!\^)")
# Each pattern is scanned forward from every start position fired by the
# corresponding inline rule. The end-pattern itself is bounded; the cost
# comes from the surrounding parser invoking the scan at every '~~' / '==' / '^^'
# token in the input, giving N starts × O(N) per scan = O(N^2) total.
Why it's wrong: the same algorithmic-complexity flaw class as [ / [a parsing in core: a per-token retry loop without memoisation of failed positions. Each formatting marker is tried as both a potential start and as a continuation. A linear-pass delimiter-stack algorithm (matching how commonmark-py and markdown-it-py handle emphasis) would do this work in O(N) total. The bounded regex on each individual scan does not bound the parser-level repetition.
Exploit Chain
- Application uses mistune to render user-supplied markdown and has any of the formatting plugins enabled (
plugins=['strikethrough'],['mark'],['insert'], or any superset). These plugins are commonly enabled because GitHub-flavoured-Markdown compatibility requires~~strikethrough~~and many editors emit==highlighting==and^^underline^^shortcuts. - Attacker submits an 8 KB markdown payload of the form
~~x~~~~x~~~~x~~...(40 000 characters of~~x~~repeated 8000 times, or the analogous shape with==/^^). - Server calls
mistune.create_markdown(plugins=['strikethrough'])(payload). CPU pegs for ~4 seconds; 16 KB → ~17 seconds; 32 KB → ~70 seconds. Pure CPU cost, no significant memory growth. - Repeating the request floods the worker pool. On a single-thread WSGI handler this is one request per outage; on a thread pool, a small number of concurrent attackers exhausts capacity.
Security Impact
Severity: sec-high. Network-reachable, no authentication, predictable scaling, single-payload primitive. Only requires a user-supplied markdown sink and a formatting plugin enabled — both are common.
Attacker capability: small input → large CPU. Doubling input size quadruples CPU time. Sustained requests deny service to other users.
Preconditions: application uses mistune with any of strikethrough, mark, or insert plugins enabled. Default config does NOT enable these (so the attack only fires against the substantial deployed population that turns them on for GFM/markdown-extra compatibility).
Differential: PoC-verified against [email protected]:
import mistune, time
md = mistune.create_markdown(plugins=['strikethrough'])
for n in [500, 1000, 2000, 4000, 8000]:
s = '~~x~~' * n
t = time.time()
md(s)
print(f' ~~x~~ * {n} ({len(s)}b): {(time.time()…
- Record
GHSA-c8j7-8cv4-2xmq- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-1333, CWE-407
- Updated
- 2026-11-02
OSVPYSEC-2026-2210
7.5
Mistune is a Python Markdown parser with renderers and plugins. Prior to 3.3.0, a run of closed tilde, equals-sign, or caret marker pairs around a character causes quadratic work in src/mistune/plugins/formatting.py when the strikethrough, mark, or insert plugin scans for matching markers from each possible start position, allowing denial of service through CPU exhaustion. This issue is fixed in version 3.3.0.
- Record
PYSEC-2026-2210- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Updated
- 2026-11-02
OSVUBUNTU-CVE-2026-59922
7.5
Mistune is a Python Markdown parser with renderers and plugins. Prior to 3.3.0, a run of closed tilde, equals-sign, or caret marker pairs around a character causes quadratic work in src/mistune/plugins/formatting.py when the strikethrough, mark, or insert plugin scans for matching markers from each possible start position, allowing denial of service through CPU exhaustion. This issue is fixed in version 3.3.0.
- Record
UBUNTU-CVE-2026-59922- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Updated
- 2026-11-02
OSVAZL-92220 No score
CVE-2026-59922 affecting package python-mistune for versions less than 3.3.0-1
Mistune is a Python Markdown parser with renderers and plugins. Prior to 3.3.0, a run of closed tilde, equals-sign, or caret marker pairs around a character causes quadratic work in src/mistune/plugins/formatting.py when the strikethrough, mark, or insert plugin scans for matching markers from each possible start position, allowing denial of service through CPU exhaustion. This issue is fixed in version 3.3.0.
- Record
AZL-92220- Updated
- 2026-11-02
OSVopenSUSE-SU-2026:21339-1 No score
Security update for python-mistune
This update for python-mistune fixes the following issues
- CVE-2026-59922: quadratic-time parsing on long runs of some markers in
formatting.pycan lead to DoS (bsc#1271117). - CVE-2026-59923:
HTMLRenderer.safe_url()does not block percent-encoded javascript URIs and allows for XSS (bsc#1271119). - CVE-2026-59924: improper processing of user-supplied include paths in
Include.parse()can lead to path traversal and arbitrary file reads (bsc#1271121). - CVE-2026-59925: quadratic-time parsing on long runs of some emphasis pairs in
inline_parsercan lead to DoS (bsc#1271125). - CVE-2026-59926: improper escaping in
render_admonition()can lead to atribute injection and XSS (bsc#1271127). - CVE-2026-59927: uncontrolled recursion when processing two markdown files that include each other can lead to a DoS (bsc#1271128).
- CVE-2026-59928: quadratic-time parsing on long lists of repeated reference-link definitions in
block_parsercan lead to DoS (bsc#1271131). - CVE-2026-59929: HARMFUL_PROTOCOLS list misses legacy and chained schemes and allow arbitrary script execution in user agents (bsc#1271132).
- CVE-2026-59930: the
tocplugin andTableOfContentsdirective generate heading IDs with predictable values and allow for collisions with attacker-controlledid="toc_N"content (bsc#1271082).
- Record
openSUSE-SU-2026:21339-1- Updated
- 2026-11-02
OSVSUSE-SU-2026:22655-1 No score
Security update for python-mistune
This update for python-mistune fixes the following issues
- CVE-2026-59922: quadratic-time parsing on long runs of some markers in
formatting.pycan lead to DoS (bsc#1271117). - CVE-2026-59923:
HTMLRenderer.safe_url()does not block percent-encoded javascript URIs and allows for XSS (bsc#1271119). - CVE-2026-59924: improper processing of user-supplied include paths in
Include.parse()can lead to path traversal and arbitrary file reads (bsc#1271121). - CVE-2026-59925: quadratic-time parsing on long runs of some emphasis pairs in
inline_parsercan lead to DoS (bsc#1271125). - CVE-2026-59926: improper escaping in
render_admonition()can lead to atribute injection and XSS (bsc#1271127). - CVE-2026-59927: uncontrolled recursion when processing two markdown files that include each other can lead to a DoS (bsc#1271128).
- CVE-2026-59928: quadratic-time parsing on long lists of repeated reference-link definitions in
block_parsercan lead to DoS (bsc#1271131). - CVE-2026-59929: HARMFUL_PROTOCOLS list misses legacy and chained schemes and allow arbitrary script execution in user agents (bsc#1271132).
- CVE-2026-59930: the
tocplugin andTableOfContentsdirective generate heading IDs with predictable values and allow for collisions with attacker-controlledid="toc_N"content (bsc#1271082).
- Record
SUSE-SU-2026:22655-1- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
mistunePyPI |
before 3.3.0 | 3.3.0 |
python-mistuneAzure Linux:3 |
before 3.3.0-1 | 3.3.0-1 |
mistuneDebian:13 |
All versions, plus listed versions 3.1.3-13.1.4-13.3.4-13.4.0-1 |
None known |
mistuneDebian:14 |
All versions, plus listed versions 3.1.3-13.1.4-13.3.4-13.4.0-1 |
None known |
mistunePyPI |
before 3.3.0, plus listed versions 0.1.00.2.00.3.00.3.10.4 Show 45 moreShow less0.4.10.50.5.10.60.70.7.10.7.20.7.30.7.40.80.8.10.8.20.8.30.8.42.0.02.0.0a12.0.0a22.0.0a32.0.0a42.0.0a52.0.0a62.0.0rc12.0.12.0.22.0.32.0.42.0.52.1.03.0.03.0.0a13.0.0a23.0.0a33.0.0rc13.0.0rc23.0.0rc33.0.0rc43.0.0rc53.0.13.0.23.1.03.1.13.1.23.1.33.1.43.2.0 |
3.3.0 |
python-mistuneSUSE:Linux Enterprise Server 16.0 From an advisory covering 10 CVEs |
before 3.1.3-160000.5.1 | 3.1.3-160000.5.1 |
python-mistuneSUSE:Linux Enterprise Server for SAP applications 16.0 From an advisory covering 10 CVEs |
before 3.1.3-160000.5.1 | 3.1.3-160000.5.1 |
mistuneUbuntu:16.04:LTS |
All versions, plus listed versions 0.6-20.7.1-1 |
None known |
mistuneUbuntu:18.04:LTS |
All versions, plus listed versions 0.7.4-10.8-10.8.1-10.8.3-2 |
None known |
mistuneUbuntu:20.04:LTS |
All versions, plus listed versions 0.8.4-10.8.4-2 |
None known |
Show 6 moreShow less
| Package | Affected | Fixed |
|---|---|---|
mistuneUbuntu:22.04:LTS |
All versions, plus listed versions 0.8.4-40.8.4-52.0.0-1+really0.8.4-1 |
None known |
mistuneUbuntu:24.04:LTS |
All versions, plus listed versions 2.0.4-23.0.2-1 |
None known |
mistuneUbuntu:25.10 |
All versions, plus listed versions 3.0.2-23.1.3-1 |
None known |
mistuneUbuntu:26.10 |
All versions, plus listed versions 3.1.4-1 |
None known |
mistuneUbuntu:26.04:LTS |
All versions, plus listed versions 3.1.3-13.1.4-1 |
None known |
python-mistuneopenSUSE:Leap 16.0 From an advisory covering 10 CVEs |
before 3.1.3-160000.5.1 | 3.1.3-160000.5.1 |
History
| Recorded | Changed | Sources |
|---|---|---|
| affected, facts | ||
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-59922 is a high vulnerability (CVSS 7.5) in Lepture Mistune, published July 8, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.64%, the 51st percentile. Fixed in mistune 3.3.0.
References
github.com/lepture/mistune/security/advisories/GHSA-c8j7-8cv4-2xmq
github.com/lepture/mistune/commit/96d0f57f8fe9eeb06bb4cff521962a27d7c402e7
github.com/lepture/mistune/releases/tag/v3.3.0
nvd.nist.gov/vuln/detail/CVE-2026-59922
github.com/pypa/advisory-database/tree/main/vulns/mistune/PYSEC-2026-2210.yaml
github.com/advisories/GHSA-c8j7-8cv4-2xmq
Show 25 moreShow less
github.com/CVEProject/cvelistV5/tree/main/cves/2026/59xxx/CVE-2026-59922.json
security-tracker.debian.org/tracker/CVE-2026-59922
github.com/lepture/mistune
suse.com/support/update/announcement/2026/suse-su-202622655-1
bugzilla.suse.com/1271082
bugzilla.suse.com/1271117
bugzilla.suse.com/1271119
bugzilla.suse.com/1271121
bugzilla.suse.com/1271125
bugzilla.suse.com/1271127
bugzilla.suse.com/1271128
bugzilla.suse.com/1271131
bugzilla.suse.com/1271132
suse.com/security/cve/CVE-2026-44896
suse.com/security/cve/CVE-2026-59922
suse.com/security/cve/CVE-2026-59923
suse.com/security/cve/CVE-2026-59924
suse.com/security/cve/CVE-2026-59925
suse.com/security/cve/CVE-2026-59926
suse.com/security/cve/CVE-2026-59927
suse.com/security/cve/CVE-2026-59928
suse.com/security/cve/CVE-2026-59929
suse.com/security/cve/CVE-2026-59930
ubuntu.com/security/CVE-2026-59922
cve.org/CVERecord?id=CVE-2026-59922
Left out here: 1 version and the rest of 2 source descriptions. The JSON record has them.