CVE-2026-67422
pymdown-extensions: Exponential-backtracking ReDoS in caret, tilde, betterem, and magiclink inline processors
pymdown-extensions is a collection of extensions for the Python Markdown library. In versions up to and including 11.0, four inline processors (caret, tilde, betterem, and magiclink) use regular expressions whose content groups can partition a run of delimiter characters in exponentially many ways, causing catastrophic backtracking. As a result, a single untrusted Markdown line under 50 bytes rendered with markdown.markdown() in each extension's default configuration drives the rendering thread into unbounded CPU usage that grows exponentially with input length, enabling an unauthenticated remote attacker who can submit Markdown to cause denial of service. The exposure is concrete for web applications that render user-supplied Markdown (comments, wikis, issue bodies, live preview), including any app using pymdownx.extra which bundles the vulnerable betterem default, as well as hosted docs/CI systems that build untrusted Markdown. The issue has been fixed in version 11.0.1.
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
pymdown-extensions: Exponential-backtracking ReDoS in caret, tilde, betterem, and magiclink inline processors
pymdown-extensions is a collection of extensions for the Python Markdown library. In versions up to and including 11.0, four inline processors (caret, tilde, betterem, and magiclink) use regular expressions whose content groups can partition a run of delimiter characters in exponentially many ways, causing catastrophic backtracking. As a result, a single untrusted Markdown line under 50 bytes rendered with markdown.markdown() in each extension's default configuration drives the rendering thread into unbounded CPU usage that grows exponentially with input length, enabling an unauthenticated remote attacker who can submit Markdown to cause denial of service. The exposure is concrete for web applications that render user-supplied Markdown (comments, wikis, issue bodies, live preview), including any app using pymdownx.extra which bundles the vulnerable betterem default, as well as hosted docs/CI systems that build untrusted Markdown. The issue has been fixed in version 11.0.1.
- Record
CVE-2026-67422- 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
- Updated
- 2026-11-02
EUVDEUVD-2026-54256
7.5
pymdown-extensions is a collection of extensions for the Python Markdown library. In versions up to and including 11.0, four inline processors (caret, tilde, betterem, and magiclink) use regular expressions whose content groups can partition a run of delimiter characters in exponentially many ways, causing catastrophic backtracking. As a result, a single untrusted Markdown line under 50 bytes rendered with markdown.markdown() in each extension's default configuration drives the rendering thread into unbounded CPU usage that grows exponentially with input length, enabling an unauthenticated remote attacker who can submit Markdown to cause denial of service. The exposure is concrete for web applications that render user-supplied Markdown (comments, wikis, issue bodies, live preview), including any app using pymdownx.extra which bundles the vulnerable betterem default, as well as hosted docs/CI systems that build untrusted Markdown. The issue has been fixed in version 11.0.1.
- Record
EUVD-2026-54256- 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-gm37-52c6-37mw
7.5
pymdown-extensions: exponential-backtracking ReDoS in caret, tilde, betterem, and magiclink inline processors
Summary
Four inline processors in pymdown-extensions contain regular expressions with
exponential backtracking. A single untrusted Markdown line under
50 bytes drives markdown.markdown() into unbounded CPU on the rendering thread
(seconds at ~45 bytes, growing exponentially with each added character). All four
fire in the extension's default configuration
and are reachable through the documented public API. The caret/tilde/
betterem blow-up was introduced by the emphasis-pattern rewrite in PR #2547
(first released in 10.13, Dec 2024) — earlier releases used a linear
(.+?) / ([^\s]+?) content group — and is present through 11.0 (latest);
magiclink's host pattern is long-standing and affects effectively all releases.
Likely CWE-1333 (Inefficient Regular Expression Complexity).
This is a distinct issue from CVE-2025-68142 (ReDoS in pymdownx.blocks.caption,
RE_FIG_NUM, fixed in 10.16.1): different extensions, different regexes, and a
different root cause (delimiter-run partition ambiguity rather than a ./\.
typo).
Details
Four regexes share, or closely mirror, a vulnerable shape — an inner group that
can partition a run of the delimiter character into {2,}-sized pieces in
exponentially many ways, wrapped in a lazy +? that must fail before the engine
can give up:
| Extension | Regex | Location (11.0) |
|---|---|---|
| pymdownx.caret (superscript ^…^) | SUP2 | pymdownx/caret.py:56 |
| pymdownx.tilde (subscript ~…~) | SUB2 | pymdownx/tilde.py:55 |
| pymdownx.betterem (underscore _…_) | SMART_UNDER_EM2 (default) | pymdownx/betterem.py:93 |
| pymdownx.magiclink (bare-URL autolink) | RE_LINK | pymdownx/magiclink.py:56 (host at :59) |
pymdownx/caret.py:56 (pymdown-extensions 11.0):
SUP2 = r'(?<!\^)(\^)(?![\^\s])((?:[^\^\s]|\^{2,})+?)(?<![\^\s])(\^)(?!\^)'
The content group (?:[^\^\s]|\^{2,})+? matches a run of carets only via the
\^{2,} branch. A run of k carets can be split into ≥2-length pieces in
exponentially many combinations; when no caret can serve as a valid closing
delimiter (the trailing (?<![\^\s])(\^) cannot be satisfied), the engine
explores every partition before failing. SUB2 (tilde) and SMART_UNDER_EM2
(betterem) are the same construct for ~ and _. In betterem the default
smart_enable='underscore' routes underscores to SmartUnderscoreProcessor →
SMART_UNDER_EM2 (betterem.py:93), which is the default-reachable,
API-exploitable pattern; the non-smart UNDER_EM2 (:69, used only when
smart_enable is asterisk/disable) shares the shape but did not reproduce
through the public markdown.markdown() pipeline on the tested payload, so a fix
and regression test should target SMART_UNDER_EM2.
pymdownx/magiclink.py:59 has the analogous ambiguity in the host portion, where
overlapping character classes let a run of dots be grouped exponentially:
(?:ht|f)tps?://[^_\W][-\w]*(?:\.[-\w.]+)* # host: '\.' and '[-\w.]' inside (?:...)* both match '.'
SUP2/SUB2/SMART_UNDER_EM2 are applied at each delimiter occurrence via the
default PatternSequenceProcessor subclasses (pymdownx/util.py); RE_LINK is
applied by MagiclinkPattern (registered unconditionally at priority 85). In all
four cases, rendering markdown.markdown(src, extensions=[ext]) on untrusted
src in default configuration is sufficient to reach the regex.
PoC
Single self-contained script; runs against the pinned release in an ephemeral env. Non-destructive — the input is ordinary Markdown text; the impact is CPU/time (a per-render alarm caps each attempt so the script terminates).
import signal
import time
from importlib.metadata import version
import markdown
print(f"# pymdown-extensions {version('pymdown-extensions')} / markdown {version('markdown')}")
CAP = 5.0 # a single render exceeding this is treated as a hang
class Timeout(Exception):
pass
def…
- Record
GHSA-gm37-52c6-37mw- 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
- Updated
- 2026-11-02
NVD
7.5
pymdown-extensions is a collection of extensions for the Python Markdown library. In versions up to and including 11.0, four inline processors (caret, tilde, betterem, and magiclink) use regular expressions whose content groups can partition a run of delimiter characters in exponentially many ways, causing catastrophic backtracking. As a result, a single untrusted Markdown line under 50 bytes rendered with markdown.markdown() in each extension's default configuration drives the rendering thread into unbounded CPU usage that grows exponentially with input length, enabling an unauthenticated remote attacker who can submit Markdown to cause denial of service. The exposure is concrete for web applications that render user-supplied Markdown (comments, wikis, issue bodies, live preview), including any app using pymdownx.extra which bundles the vulnerable betterem default, as well as hosted docs/CI systems that build untrusted Markdown. The issue has been fixed in version 11.0.1.
- Record
CVE-2026-67422- 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
- Updated
- 2026-11-02
OSV
7.5
pymdown-extensions: Exponential-backtracking ReDoS in caret, tilde, betterem, and magiclink inline processors
pymdown-extensions is a collection of extensions for the Python Markdown library. In versions up to and including 11.0, four inline processors (caret, tilde, betterem, and magiclink) use regular expressions whose content groups can partition a run of delimiter characters in exponentially many ways, causing catastrophic backtracking. As a result, a single untrusted Markdown line under 50 bytes rendered with markdown.markdown() in each extension's default configuration drives the rendering thread into unbounded CPU usage that grows exponentially with input length, enabling an unauthenticated remote attacker who can submit Markdown to cause denial of service. The exposure is concrete for web applications that render user-supplied Markdown (comments, wikis, issue bodies, live preview), including any app using pymdownx.extra which bundles the vulnerable betterem default, as well as hosted docs/CI systems that build untrusted Markdown. The issue has been fixed in version 11.0.1.
- Record
CVE-2026-67422- 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
- Updated
- 2026-11-02
OSVDEBIAN-CVE-2026-67422
7.5
pymdown-extensions is a collection of extensions for the Python Markdown library. In versions up to and including 11.0, four inline processors (caret, tilde, betterem, and magiclink) use regular expressions whose content groups can partition a run of delimiter characters in exponentially many ways, causing catastrophic backtracking. As a result, a single untrusted Markdown line under 50 bytes rendered with markdown.markdown() in each extension's default configuration drives the rendering thread into unbounded CPU usage that grows exponentially with input length, enabling an unauthenticated remote attacker who can submit Markdown to cause denial of service. The exposure is concrete for web applications that render user-supplied Markdown (comments, wikis, issue bodies, live preview), including any app using pymdownx.extra which bundles the vulnerable betterem default, as well as hosted docs/CI systems that build untrusted Markdown. The issue has been fixed in version 11.0.1.
- Record
DEBIAN-CVE-2026-67422- 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 7 moreShow less
OSVGHSA-gm37-52c6-37mw
7.5
pymdown-extensions: exponential-backtracking ReDoS in caret, tilde, betterem, and magiclink inline processors
Summary
Four inline processors in pymdown-extensions contain regular expressions with
exponential backtracking. A single untrusted Markdown line under
50 bytes drives markdown.markdown() into unbounded CPU on the rendering thread
(seconds at ~45 bytes, growing exponentially with each added character). All four
fire in the extension's default configuration
and are reachable through the documented public API. The caret/tilde/
betterem blow-up was introduced by the emphasis-pattern rewrite in PR #2547
(first released in 10.13, Dec 2024) — earlier releases used a linear
(.+?) / ([^\s]+?) content group — and is present through 11.0 (latest);
magiclink's host pattern is long-standing and affects effectively all releases.
Likely CWE-1333 (Inefficient Regular Expression Complexity).
This is a distinct issue from CVE-2025-68142 (ReDoS in pymdownx.blocks.caption,
RE_FIG_NUM, fixed in 10.16.1): different extensions, different regexes, and a
different root cause (delimiter-run partition ambiguity rather than a ./\.
typo).
Details
Four regexes share, or closely mirror, a vulnerable shape — an inner group that
can partition a run of the delimiter character into {2,}-sized pieces in
exponentially many ways, wrapped in a lazy +? that must fail before the engine
can give up:
| Extension | Regex | Location (11.0) |
|---|---|---|
| pymdownx.caret (superscript ^…^) | SUP2 | pymdownx/caret.py:56 |
| pymdownx.tilde (subscript ~…~) | SUB2 | pymdownx/tilde.py:55 |
| pymdownx.betterem (underscore _…_) | SMART_UNDER_EM2 (default) | pymdownx/betterem.py:93 |
| pymdownx.magiclink (bare-URL autolink) | RE_LINK | pymdownx/magiclink.py:56 (host at :59) |
pymdownx/caret.py:56 (pymdown-extensions 11.0):
SUP2 = r'(?<!\^)(\^)(?![\^\s])((?:[^\^\s]|\^{2,})+?)(?<![\^\s])(\^)(?!\^)'
The content group (?:[^\^\s]|\^{2,})+? matches a run of carets only via the
\^{2,} branch. A run of k carets can be split into ≥2-length pieces in
exponentially many combinations; when no caret can serve as a valid closing
delimiter (the trailing (?<![\^\s])(\^) cannot be satisfied), the engine
explores every partition before failing. SUB2 (tilde) and SMART_UNDER_EM2
(betterem) are the same construct for ~ and _. In betterem the default
smart_enable='underscore' routes underscores to SmartUnderscoreProcessor →
SMART_UNDER_EM2 (betterem.py:93), which is the default-reachable,
API-exploitable pattern; the non-smart UNDER_EM2 (:69, used only when
smart_enable is asterisk/disable) shares the shape but did not reproduce
through the public markdown.markdown() pipeline on the tested payload, so a fix
and regression test should target SMART_UNDER_EM2.
pymdownx/magiclink.py:59 has the analogous ambiguity in the host portion, where
overlapping character classes let a run of dots be grouped exponentially:
(?:ht|f)tps?://[^_\W][-\w]*(?:\.[-\w.]+)* # host: '\.' and '[-\w.]' inside (?:...)* both match '.'
SUP2/SUB2/SMART_UNDER_EM2 are applied at each delimiter occurrence via the
default PatternSequenceProcessor subclasses (pymdownx/util.py); RE_LINK is
applied by MagiclinkPattern (registered unconditionally at priority 85). In all
four cases, rendering markdown.markdown(src, extensions=[ext]) on untrusted
src in default configuration is sufficient to reach the regex.
PoC
Single self-contained script; runs against the pinned release in an ephemeral env. Non-destructive — the input is ordinary Markdown text; the impact is CPU/time (a per-render alarm caps each attempt so the script terminates).
import signal
import time
from importlib.metadata import version
import markdown
print(f"# pymdown-extensions {version('pymdown-extensions')} / markdown {version('markdown')}")
CAP = 5.0 # a single render exceeding this is treated as a hang
class Timeout(Exception):
pass
def…
- Record
GHSA-gm37-52c6-37mw- 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
- Updated
- 2026-11-02
OSVOESA-2026-4182
7.5
python-pymdown-extensions security update
Extension pack for Python Markdown.
Security Fix(es):
PyMdown Extensions is a set of extensions for the Python-Markdown markdown project. From 10.0.1 until 10.21.3, pymdownx.snippets uses a string-prefix containment check in SnippetPreprocessor.get_snippet_path() in pymdownx/snippets.py when restrict_base_path: True, allowing markdown snippet directives to read files from sibling paths that share the same base_path prefix, such as docs and docs_internal. This is a regression of CVE-2023-32309. This issue is fixed in version 10.21.3.(CVE-2026-46338)
PyMdown Extensions is a set of extensions for the Python-Markdown markdown project. In versions up to and including 10.21.3, the b64 extension is vulnerable to a path traversal that discloses arbitrary files: it inlines images referenced by <img src="..."> by joining the src onto the configured base_path with os.path.normpath and opening the result directly, without verifying that the resolved path stays inside base_path. As a result, an src containing ../ sequences or an absolute path reads a file outside base_path as long as it has an allowed image extension (.png, .jpg, .jpeg, .gif, .svg), and the file's contents are then base64-encoded into the rendered output, disclosing them. An application that renders untrusted Markdown with pymdownx.b64 enabled can therefore leak the contents of image-extension files readable by the process to whoever controls the Markdown or views the output, a targeted file-read bounded by the extension check. This issue has been fixed in version 11.0.(CVE-2026-61632)
pymdown-extensions is a collection of extensions for the Python Markdown library. In versions up to and including 11.0, four inline processors (caret, tilde, betterem, and magiclink) use regular expressions whose content groups can partition a run of delimiter characters in exponentially many ways, causing catastrophic backtracking. As a result, a single untrusted Markdown line under 50 bytes rendered with markdown.markdown() in each extension's default configuration drives the rendering thread into unbounded CPU usage that grows exponentially with input length, enabling an unauthenticated remote attacker who can submit Markdown to cause denial of service. The exposure is concrete for web applications that render user-supplied Markdown (comments, wikis, issue bodies, live preview), including any app using pymdownx.extra which bundles the vulnerable betterem default, as well as hosted docs/CI systems that build untrusted Markdown. The issue has been fixed in version 11.0.1.(CVE-2026-67422)
- Record
OESA-2026-4182- 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
OSVOESA-2026-4183
7.5
python-pymdown-extensions security update
Extension pack for Python Markdown.
Security Fix(es):
PyMdown Extensions is a set of extensions for the Python-Markdown markdown project. From 10.0.1 until 10.21.3, pymdownx.snippets uses a string-prefix containment check in SnippetPreprocessor.get_snippet_path() in pymdownx/snippets.py when restrict_base_path: True, allowing markdown snippet directives to read files from sibling paths that share the same base_path prefix, such as docs and docs_internal. This is a regression of CVE-2023-32309. This issue is fixed in version 10.21.3.(CVE-2026-46338)
PyMdown Extensions is a set of extensions for the Python-Markdown markdown project. In versions up to and including 10.21.3, the b64 extension is vulnerable to a path traversal that discloses arbitrary files: it inlines images referenced by <img src="..."> by joining the src onto the configured base_path with os.path.normpath and opening the result directly, without verifying that the resolved path stays inside base_path. As a result, an src containing ../ sequences or an absolute path reads a file outside base_path as long as it has an allowed image extension (.png, .jpg, .jpeg, .gif, .svg), and the file's contents are then base64-encoded into the rendered output, disclosing them. An application that renders untrusted Markdown with pymdownx.b64 enabled can therefore leak the contents of image-extension files readable by the process to whoever controls the Markdown or views the output, a targeted file-read bounded by the extension check. This issue has been fixed in version 11.0.(CVE-2026-61632)
pymdown-extensions is a collection of extensions for the Python Markdown library. In versions up to and including 11.0, four inline processors (caret, tilde, betterem, and magiclink) use regular expressions whose content groups can partition a run of delimiter characters in exponentially many ways, causing catastrophic backtracking. As a result, a single untrusted Markdown line under 50 bytes rendered with markdown.markdown() in each extension's default configuration drives the rendering thread into unbounded CPU usage that grows exponentially with input length, enabling an unauthenticated remote attacker who can submit Markdown to cause denial of service. The exposure is concrete for web applications that render user-supplied Markdown (comments, wikis, issue bodies, live preview), including any app using pymdownx.extra which bundles the vulnerable betterem default, as well as hosted docs/CI systems that build untrusted Markdown. The issue has been fixed in version 11.0.1.(CVE-2026-67422)
- Record
OESA-2026-4183- 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
OSVOESA-2026-4184
7.5
python-pymdown-extensions security update
Extension pack for Python Markdown.
Security Fix(es):
PyMdown Extensions is a set of extensions for the Python-Markdown markdown project. From 10.0.1 until 10.21.3, pymdownx.snippets uses a string-prefix containment check in SnippetPreprocessor.get_snippet_path() in pymdownx/snippets.py when restrict_base_path: True, allowing markdown snippet directives to read files from sibling paths that share the same base_path prefix, such as docs and docs_internal. This is a regression of CVE-2023-32309. This issue is fixed in version 10.21.3.(CVE-2026-46338)
PyMdown Extensions is a set of extensions for the Python-Markdown markdown project. In versions up to and including 10.21.3, the b64 extension is vulnerable to a path traversal that discloses arbitrary files: it inlines images referenced by <img src="..."> by joining the src onto the configured base_path with os.path.normpath and opening the result directly, without verifying that the resolved path stays inside base_path. As a result, an src containing ../ sequences or an absolute path reads a file outside base_path as long as it has an allowed image extension (.png, .jpg, .jpeg, .gif, .svg), and the file's contents are then base64-encoded into the rendered output, disclosing them. An application that renders untrusted Markdown with pymdownx.b64 enabled can therefore leak the contents of image-extension files readable by the process to whoever controls the Markdown or views the output, a targeted file-read bounded by the extension check. This issue has been fixed in version 11.0.(CVE-2026-61632)
pymdown-extensions is a collection of extensions for the Python Markdown library. In versions up to and including 11.0, four inline processors (caret, tilde, betterem, and magiclink) use regular expressions whose content groups can partition a run of delimiter characters in exponentially many ways, causing catastrophic backtracking. As a result, a single untrusted Markdown line under 50 bytes rendered with markdown.markdown() in each extension's default configuration drives the rendering thread into unbounded CPU usage that grows exponentially with input length, enabling an unauthenticated remote attacker who can submit Markdown to cause denial of service. The exposure is concrete for web applications that render user-supplied Markdown (comments, wikis, issue bodies, live preview), including any app using pymdownx.extra which bundles the vulnerable betterem default, as well as hosted docs/CI systems that build untrusted Markdown. The issue has been fixed in version 11.0.1.(CVE-2026-67422)
- Record
OESA-2026-4184- 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
OSVPYSEC-2026-3654
7.5
pymdown-extensions: exponential-backtracking ReDoS in caret, tilde, betterem, and magiclink inline processors
Summary
Four inline processors in pymdown-extensions contain regular expressions with
exponential backtracking. A single untrusted Markdown line under
50 bytes drives markdown.markdown() into unbounded CPU on the rendering thread
(seconds at ~45 bytes, growing exponentially with each added character). All four
fire in the extension's default configuration
and are reachable through the documented public API. The caret/tilde/
betterem blow-up was introduced by the emphasis-pattern rewrite in PR #2547
(first released in 10.13, Dec 2024) — earlier releases used a linear
(.+?) / ([^\s]+?) content group — and is present through 11.0 (latest);
magiclink's host pattern is long-standing and affects effectively all releases.
Likely CWE-1333 (Inefficient Regular Expression Complexity).
This is a distinct issue from CVE-2025-68142 (ReDoS in pymdownx.blocks.caption,
RE_FIG_NUM, fixed in 10.16.1): different extensions, different regexes, and a
different root cause (delimiter-run partition ambiguity rather than a ./\.
typo).
Details
Four regexes share, or closely mirror, a vulnerable shape — an inner group that
can partition a run of the delimiter character into {2,}-sized pieces in
exponentially many ways, wrapped in a lazy +? that must fail before the engine
can give up:
| Extension | Regex | Location (11.0) |
|---|---|---|
| pymdownx.caret (superscript ^…^) | SUP2 | pymdownx/caret.py:56 |
| pymdownx.tilde (subscript ~…~) | SUB2 | pymdownx/tilde.py:55 |
| pymdownx.betterem (underscore _…_) | SMART_UNDER_EM2 (default) | pymdownx/betterem.py:93 |
| pymdownx.magiclink (bare-URL autolink) | RE_LINK | pymdownx/magiclink.py:56 (host at :59) |
pymdownx/caret.py:56 (pymdown-extensions 11.0):
SUP2 = r'(?<!\^)(\^)(?![\^\s])((?:[^\^\s]|\^{2,})+?)(?<![\^\s])(\^)(?!\^)'
The content group (?:[^\^\s]|\^{2,})+? matches a run of carets only via the
\^{2,} branch. A run of k carets can be split into ≥2-length pieces in
exponentially many combinations; when no caret can serve as a valid closing
delimiter (the trailing (?<![\^\s])(\^) cannot be satisfied), the engine
explores every partition before failing. SUB2 (tilde) and SMART_UNDER_EM2
(betterem) are the same construct for ~ and _. In betterem the default
smart_enable='underscore' routes underscores to SmartUnderscoreProcessor →
SMART_UNDER_EM2 (betterem.py:93), which is the default-reachable,
API-exploitable pattern; the non-smart UNDER_EM2 (:69, used only when
smart_enable is asterisk/disable) shares the shape but did not reproduce
through the public markdown.markdown() pipeline on the tested payload, so a fix
and regression test should target SMART_UNDER_EM2.
pymdownx/magiclink.py:59 has the analogous ambiguity in the host portion, where
overlapping character classes let a run of dots be grouped exponentially:
(?:ht|f)tps?://[^_\W][-\w]*(?:\.[-\w.]+)* # host: '\.' and '[-\w.]' inside (?:...)* both match '.'
SUP2/SUB2/SMART_UNDER_EM2 are applied at each delimiter occurrence via the
default PatternSequenceProcessor subclasses (pymdownx/util.py); RE_LINK is
applied by MagiclinkPattern (registered unconditionally at priority 85). In all
four cases, rendering markdown.markdown(src, extensions=[ext]) on untrusted
src in default configuration is sufficient to reach the regex.
PoC
Single self-contained script; runs against the pinned release in an ephemeral env. Non-destructive — the input is ordinary Markdown text; the impact is CPU/time (a per-render alarm caps each attempt so the script terminates).
import signal
import time
from importlib.metadata import version
import markdown
print(f"# pymdown-extensions {version('pymdown-extensions')} / markdown {version('markdown')}")
CAP = 5.0 # a single render exceeding this is treated as a hang
class Timeout(Exception):
pass
def…
- Record
PYSEC-2026-3654- 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-67422
7.5
pymdown-extensions is a collection of extensions for the Python Markdown library. In versions up to and including 11.0, four inline processors (caret, tilde, betterem, and magiclink) use regular expressions whose content groups can partition a run of delimiter characters in exponentially many ways, causing catastrophic backtracking. As a result, a single untrusted Markdown line under 50 bytes rendered with markdown.markdown() in each extension's default configuration drives the rendering thread into unbounded CPU usage that grows exponentially with input length, enabling an unauthenticated remote attacker who can submit Markdown to cause denial of service. The exposure is concrete for web applications that render user-supplied Markdown (comments, wikis, issue bodies, live preview), including any app using pymdownx.extra which bundles the vulnerable betterem default, as well as hosted docs/CI systems that build untrusted Markdown. The issue has been fixed in version 11.0.1.
- Record
UBUNTU-CVE-2026-67422- 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
OSVROOT-APP-PYPI-CVE-2026-67422 No score
CVE-2026-67422 in pymdown-extensions - Patched by Root
Root has patched CVE-2026-67422 in the pymdown-extensions package for Root:PyPI. Multiple fixed versions available.
- Record
ROOT-APP-PYPI-CVE-2026-67422- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
pymdown-extensionsPyPI |
through 11.0.0 | 11.0.1 |
pymdown-extensionsDebian:12 |
All versions, plus listed versions 10.11.2-110.13-110.13-210.13-310.13-4 Show 9 moreShow less10.19.1-110.19.1-310.8.1-110.9-111.0.1-19.5-29.5-39.5-49.5-5 |
None known |
pymdown-extensionsDebian:13 |
All versions, plus listed versions 10.13-110.13-1+deb13u110.13-210.13-310.13-410.19.1-110.19.1-311.0.1-1 |
None known |
pymdown-extensionsDebian:14 |
before 11.0.1-1, plus listed versions 10.13-110.13-210.13-310.13-410.19.1-110.19.1-3 |
11.0.1-1 |
pymdown-extensionsPyPI |
before 11.0.1, plus listed versions 1.0.01.0.11.11.21.3 Show 45 moreShow less1.41.51.61.6.11.71.810.010.0.110.110.1010.10.110.10.210.1110.11.110.11.210.1210.1310.1410.14.110.14.210.14.310.1510.1610.16.110.1710.17.110.17.210.1810.1910.19.110.210.2.110.2010.20.110.2110.21.210.21.310.310.3.110.410.510.610.710.7.110.8 |
11.0.1 |
python-pymdown-extensionsopenEuler:24.03-LTS-SP4 From an advisory covering 3 CVEs |
before 10.7-3.oe2403sp4 | 10.7-3.oe2403sp4 |
python-pymdown-extensionsopenEuler:24.03-LTS-SP1 From an advisory covering 3 CVEs |
before 10.7-3.oe2403sp1 | 10.7-3.oe2403sp1 |
python-pymdown-extensionsopenEuler:24.03-LTS-SP3 From an advisory covering 3 CVEs |
before 10.7-3.oe2403sp3 | 10.7-3.oe2403sp3 |
pymdown-extensionsRoot:PyPI |
before 10.21.2+aikido.2 | 10.21.2+aikido.211.0+aikido.2 |
pymdown-extensionsUbuntu:24.04:LTS |
All versions, plus listed versions 9.5-29.5-49.5-5 |
None known |
pymdown-extensionsUbuntu:26.04:LTS |
All versions, plus listed versions 10.13-310.13-410.19.1-3 |
None known |
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-67422 is a high vulnerability (CVSS 7.5) in Facelessuser Pymdown-extensions, published August 6, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.61%, the 49th percentile. Fixed in pymdown-extensions 11.0.1.
References
github.com/facelessuser/pymdown-extensions/security/advisories/GHSA-gm37-52c6-37mw
github.com/facelessuser/pymdown-extensions/commit/c68498598d7b13011bb4571350b6e3612a4ce44b
nvd.nist.gov/vuln/detail/CVE-2026-67422
github.com/advisories/GHSA-gm37-52c6-37mw
github.com/CVEProject/cvelistV5/tree/main/cves/2026/67xxx/CVE-2026-67422.json
security-tracker.debian.org/tracker/CVE-2026-67422
Show 9 moreShow less
github.com/facelessuser/pymdown-extensions
openeuler.org/zh/security/security-bulletins/detail?id=openEuler-SA-2026-4182
nvd.nist.gov/vuln/detail/CVE-2026-46338
nvd.nist.gov/vuln/detail/CVE-2026-61632
openeuler.org/zh/security/security-bulletins/detail?id=openEuler-SA-2026-4183
openeuler.org/zh/security/security-bulletins/detail?id=openEuler-SA-2026-4184
pypi.org/project/pymdown-extensions
ubuntu.com/security/CVE-2026-67422
cve.org/CVERecord?id=CVE-2026-67422
Left out here: 69 versions and the rest of 3 source descriptions. The JSON record has them.