---
id: "CVE-2026-115774"
kind: "vulnerability"
aliases: ["CVE-2026-115774", "GHSA-2qrf-pqgx-qh9v"]
title: "Twisted: Denial of Service in the Twisted IMAP4 Server via a Negative Literal Size in SEARCH"
severity: "medium"
cvss: 4.9
epss: null
exploited: false
status: "open"
category: "package"
products: [{"name": "Twisted", "fixed": ["26.10.0rc1"], "affected": "<= 26.4.0", "ecosystem": "pypi"}]
ecosystems: ["pypi"]
tags: ["cwe-400", "cwe-835", "imap", "package", "python", "self-hosted", "twisted"]
not_affected_if: ["auth-required", "managed-hosting", "no-imap-server"]
published_at: "2026-10-23T20:46:12+00:00"
first_seen_at: "2026-10-23T20:59:05+00:00"
updated_at: "2026-10-23T21:00:24+00:00"
sources: [{"source": "ghsa", "url": "https://github.com/advisories/GHSA-2qrf-pqgx-qh9v", "first_seen_at": "2026-10-23T20:59:05+00:00"}, {"source": "nvd", "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-115774", "first_seen_at": "2026-10-23T21:57:34+00:00"}]
---

# Twisted: Denial of Service in the Twisted IMAP4 Server via a Negative Literal Size in SEARCH

Twisted's IMAP4 server freezes its single-threaded process when a logged-in client sends a SEARCH with a negative literal size such as {-100}. An attacker with any valid mail account can stop every service in that process with one short command.

_Summary, check and fix written by a model from the sources; labelled as such._

## Affected

- pypi:Twisted affected <= 26.4.0 fixed 26.10.0rc1

## How to check

Run pip show Twisted and check whether the version is 26.4.0 or earlier.
Check whether the app imports twisted.mail.imap4 or runs twistd mail.

## Fix

Upgrade Twisted to 26.10.0rc1 or later (fixed version per sources; check for a final release).
Restart the process after upgrading if it hung.

## Timeline

- 2026-10-23T20:59:05+00:00 ghsa https://github.com/advisories/GHSA-2qrf-pqgx-qh9v
- 2026-10-23T21:57:34+00:00 nvd https://nvd.nist.gov/vuln/detail/CVE-2026-115774

## From the sources

## Summary

An infinite-loop vulnerability (CWE-835) in the Twisted IMAP4 server lets an authenticated client freeze the whole process with one small command. `twisted.mail.imap4.parseNestedParens` reads an IMAP literal size with `int()` and never rejects a negative value. A negative size such as `{-100}` drives the parser cursor negative, and because a negative Python index wraps around the end of the string instead of raising, the scanning loop never terminates. It runs synchronously on the single-threaded reactor, so one `SEARCH` command holds the reactor at full CPU forever and every other connection stops being served.

## Details

Meeting an inline literal, `parseNestedParens` reads the size between the braces and advances the cursor past the body:

```python
# twisted/mail/imap4.py  parseNestedParens
literalSize = int(s[i + 1 : end])          # no sign check
contentStack[-1].append((s[end + 3 : end + 3 + literalSize],))
i = end + 3 + literalSize                    # negative size -> i goes negative
```

`int(b"-100")` is `-100`, so `i` goes negative; the loop condition `i < len(s)` stays true and `s[i : i + 1]` on a negative index never raises, so the cursor cycles forever. The `_literalStringLimit` guard only covers the synchronizing-literal continuation path, not this inline branch. The call is reached from `select_SEARCH` through `arg_searchkeys`, dispatched only in the selected state, so a valid login and a selected mailbox (any low-privilege account) suffice. It runs in the reactor thread, and the connection timeout cannot fire because the reactor itself is frozen.

Affected product: Twisted (`twisted.mail`), the IMAP4 server `twisted.mail.imap4.IMAP4Server`
Affected versions: 26.4.0 and earlier

## PoC

Log in, select a mailbox, and send a `SEARCH` whose literal size is negative:

```text
C: t1 LOGIN testuser password-test
C: t2 SELECT INBOX
C: t3 SEARCH {-100}zzzzzzzzzz
```

The server never responds and one core stays at 100 percent. In a measured run a health service co-hosted on the same reactor stopped answering the instant the command arrived, showing the freeze hits the whole process and not just the attacking connection. A valid `{5}zzzzz` completes normally and a non-numeric `{abc}` is rejected with a parse error, which isolates the cause to the missing negative-size check.

## Impact

A remote denial of service. One command of about ten bytes freezes the single-threaded reactor, so it stops serving not only every other IMAP connection but every other service co-hosted in the same process (for example SMTP and POP3 under `twistd mail`), and no timeout can recover it until the process is restarted. It requires an authenticated session, so any account holder can trigger it; there is no confidentiality or integrity impact and no code execution.

---

_Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai_
