CVE-2026-106454

mediumpriority · track · 0EPSS 0.004 · 36 %ileUS
grimoire priorityP3 · Track
Exploitable?
—
no known exploitation
Likely / severe?
0.42% (36th) EPSS
CVSS 4.3 · medium
Is it mine?
2 products
Check your exposure
Who says so?
1 sources
osv

EPSS · scored 2026-10-27

Twisted is an event-based framework for internet applications, supporting Python 3.6+. In 25.5.0 and earlier, wildcardToRegexp() in twisted/mail/imap4.py translates the IMAP asterisk and percent wildcards but passes all other characters from an authenticated client's LIST or LSUB pattern directly to re.compile(), allowing nested or otherwise expensive regular expression constructs to cause catastrophic backtracking when matched against mailbox names. Because Twisted uses a cooperative single-threaded reactor, the blocking match suspends all server input and output for the duration of the match. No fixed release is available as of this review.

01

cvss

Technical severity, 0–10. One row per scoring source.

4.3
010

base score 0–10 · higher = more severe · hover a vector to decode

v3.14.3mediumCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:Lsecondary · security-advisories@github.comexploitability 2.8 · impact 1.4
v3.14.3mediumCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:Lsecondary · OSV
v3.14mediumCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L/E:Usecondary · CVSS-BT (t0sche)
02

weaknesses

The CWE weakness classes this flaw belongs to.

03

affected products (2)

Products and version ranges known to be affected.

04

advisories (2)

Vendor and ecosystem advisories describing this.

  • GHSA-8pqf-f4m5-798gTwisted: IMAP wildcardToRegexp() ReDoS2026-10-07ghsa · osvUS

    ### Summary `wildcardToRegexp()` in `twisted/mail/imap4.py` converts IMAP LIST/LSUB wildcard patterns to Python regular expressions. It substitutes the two IMAP wildcards (`*` → `(?:.*?)` and `%` → `(?:(?:[^\\/])*?)`) but passes every other character through unchanged to `re.compile()`. This means that an authenticated IMAP client can send a quoted pattern string containing arbitrary regex syntax - including catastrophic-backtracking constructs such as `(a+)+z`. Because Twisted runs a cooperative, single-threaded reactor, a blocking regex match freezes **all** I/O on the server for the duration of the match. --- ## Vulnerable Code ### `twisted/mail/imap4.py` ```python # line 4595 def wildcardToRegexp(wildcard, delim=None): wildcard = wildcard.replace("*", "(?:.*?)") if delim is None: wildcard = wildcard.replace("%", "(?:.*?)") else: wildcard = wildcard.replace("%", "(?:(?:[^%s])*?)" % re.escape(delim)) return re.compile(wildcard, re.I) # ← user input compiled verbatim ``` ```python # line 4993 class MemoryAccountWithoutNamespaces: def listMailboxes(self, ref, wildcard): ref = self._inferiorNames(_parseMbox(ref.upper())) wildcard = wildcardToRegexp(wildcard, "/") # ← user-supplied wildcard return [(i, self.mailboxes[i]) for i in ref if wildcard.match(i)] ``` --- ### Proof of Concept ```python from twisted.mail.imap4 import wildcardToRegexp import time rx = wildcardToRegexp("(a+)+z", "/") for n in [20, 22, 24, 26, 28]: victim = "a" * n t0 = time.perf_counter() rx.match(victim) print(f"n={n}: {time.perf_counter() - t0:.3f}s") ``` **Output on Twisted 25.5.0:** ``` [*] Compiled regex: '(a+)+z' [*] Note: metacharacters ( ) + ? are NOT escaped - they go straight to re.compile() n time --- ---------- 20 0.153s 22 0.651s 24 2.941s 26 14.545s 28 55.019s ``` Timing doubles roughly every two characters (exponential growth), confirming catastrophic backtracking. --- ## Impact Twisted's reactor is single-threaded and cooperative. A blocking `re.match()` call suspends the entire event loop - no other connection can be accepted, read, or written while the match runs. A single authenticated LIST command with a 28-character target mailbox name can stall the server for ~55 seconds. An attacker who can register an account (or obtain credentials through other means) can: 1. `CREATE` a mailbox whose name is an exponential-blowup trigger string. 2. Issue `LIST "" "(a+)+z"` (or equivalent ReDoS pattern). 3. Repeat at ~1-minute intervals to keep the server permanently unavailable. No exploit code or special privileges beyond an IMAP login are required. --- ## Fix Escape non-wildcard characters before compiling: ```python def wildcardToRegexp(wildcard, delim=None): # Split on the two IMAP wildcards, escape everything else parts = re.split(r'([*%])', wildcard) result = [] for p in parts: if p == '*': result.append('(?:.*?)') elif p == '%': if delim is None: result.append('(?:.*?)') else: result.append('(?:(?:[^%s])*?)' % re.escape(delim)) else: result.append(re.escape(p)) # ← escape all other characters return re.compile(''.join(result), re.I) ``` Alternatively, apply `re.escape()` to the entire wildcard first, then substitute the (now-escaped) `\*` and `\%` tokens back with their regex equivalents.

  • PYSEC-2026-4304Twisted: IMAP wildcardToRegexp() ReDoS2026-10-15vendor · osvUS

    ### Summary `wildcardToRegexp()` in `twisted/mail/imap4.py` converts IMAP LIST/LSUB wildcard patterns to Python regular expressions. It substitutes the two IMAP wildcards (`*` → `(?:.*?)` and `%` → `(?:(?:[^\\/])*?)`) but passes every other character through unchanged to `re.compile()`. This means that an authenticated IMAP client can send a quoted pattern string containing arbitrary regex syntax - including catastrophic-backtracking constructs such as `(a+)+z`. Because Twisted runs a cooperative, single-threaded reactor, a blocking regex match freezes **all** I/O on the server for the duration of the match. --- ## Vulnerable Code ### `twisted/mail/imap4.py` ```python # line 4595 def wildcardToRegexp(wildcard, delim=None): wildcard = wildcard.replace("*", "(?:.*?)") if delim is None: wildcard = wildcard.replace("%", "(?:.*?)") else: wildcard = wildcard.replace("%", "(?:(?:[^%s])*?)" % re.escape(delim)) return re.compile(wildcard, re.I) # ← user input compiled verbatim ``` ```python # line 4993 class MemoryAccountWithoutNamespaces: def listMailboxes(self, ref, wildcard): ref = self._inferiorNames(_parseMbox(ref.upper())) wildcard = wildcardToRegexp(wildcard, "/") # ← user-supplied wildcard return [(i, self.mailboxes[i]) for i in ref if wildcard.match(i)] ``` --- ### Proof of Concept ```python from twisted.mail.imap4 import wildcardToRegexp import time rx = wildcardToRegexp("(a+)+z", "/") for n in [20, 22, 24, 26, 28]: victim = "a" * n t0 = time.perf_counter() rx.match(victim) print(f"n={n}: {time.perf_counter() - t0:.3f}s") ``` **Output on Twisted 25.5.0:** ``` [*] Compiled regex: '(a+)+z' [*] Note: metacharacters ( ) + ? are NOT escaped - they go straight to re.compile() n time --- ---------- 20 0.153s 22 0.651s 24 2.941s 26 14.545s 28 55.019s ``` Timing doubles roughly every two characters (exponential growth), confirming catastrophic backtracking. --- ## Impact Twisted's reactor is single-threaded and cooperative. A blocking `re.match()` call suspends the entire event loop - no other connection can be accepted, read, or written while the match runs. A single authenticated LIST command with a 28-character target mailbox name can stall the server for ~55 seconds. An attacker who can register an account (or obtain credentials through other means) can: 1. `CREATE` a mailbox whose name is an exponential-blowup trigger string. 2. Issue `LIST "" "(a+)+z"` (or equivalent ReDoS pattern). 3. Repeat at ~1-minute intervals to keep the server permanently unavailable. No exploit code or special privileges beyond an IMAP login are required. --- ## Fix Escape non-wildcard characters before compiling: ```python def wildcardToRegexp(wildcard, delim=None): # Split on the two IMAP wildcards, escape everything else parts = re.split(r'([*%])', wildcard) result = [] for p in parts: if p == '*': result.append('(?:.*?)') elif p == '%': if delim is None: result.append('(?:.*?)') else: result.append('(?:(?:[^%s])*?)' % re.escape(delim)) else: result.append(re.escape(p)) # ← escape all other characters return re.compile(''.join(result), re.I) ``` Alternatively, apply `re.escape()` to the entire wildcard first, then substitute the (now-escaped) `\*` and `\%` tokens back with their regex equivalents.

05

also known as (2)

Other names and identifiers for this entity.

06

sources

Which sources assert this record, and when.

published 2026-10-06modified 2026-10-07
07

references (3) nvd

External citations — patches, advisories, analysis.

scry

Attackers weaponise vulnerabilities like this against internet-exposed services. See what is exposed on your perimeter with a free passive scan.

Free scan