SB2026110601 - Multiple vulnerabilities in Twisted Web



SB2026110601 - Multiple vulnerabilities in Twisted Web

Published: November 6, 2026

Security Bulletin ID SB2026110601
CSH Severity
Medium
Patch available
YES
Number of vulnerabilities 7
Exploitation vector Remote access
Highest impact Denial of service

Breakdown by Severity

Medium 57% Low 43%
  • Low
  • Medium
  • High
  • Critical

Description

This security bulletin contains information about 7 vulnerabilities.


1) Resource exhaustion (CVE-ID: N/A)

CWE-ID: CWE-400 - Resource exhaustion

CVSSv4: 8.7 [CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N]


The vulnerability allows an unauthenticated remote client to exhaust CPU resources in the Twisted Web HTTP/2 server and cause denial of service over a single connection. Sustained traffic can saturate a CPU core with only a small volume of network traffic. There is no confidentiality or integrity impact and no code execution.

The vulnerability exists due to ordered processing of HTTP/2 events that dispatches and synchronously renders a completed request before handling its subsequent stream reset, combined with the absence of limits on opened-and-reset streams. A remote attacker can connect to a Twisted HTTP/2 endpoint without credentials and repeatedly send a HEADERS frame with END_STREAM on a fresh stream identifier immediately followed by RST_STREAM. Each request is rendered before its reset is processed, and the reset frees the stream so it does not accumulate against the 100-stream concurrency budget. No reset-rate limiter throttles this pattern, allowing repeated request rendering at line rate without the connection being throttled or closed.

In src/twisted/web/_http2.py, H2Connection.dataReceived processes RequestReceived, StreamEnded, and StreamReset events in order for the paired frames. The _requestReceived handler allocates the request, _requestEnded invokes request completion and synchronous rendering, and _requestAborted subsequently frees the stream. Unlike clients that leave streams open and are disconnected upon reaching the concurrent-stream limit, rapidly reset streams permit work to grow with the number of frame pairs sent. This is an HTTP/2 Rapid Reset mechanism; limits on outbound control-frame buffering do not constrain this request-processing path.


2) Origin validation error (CVE-ID: CVE-2026-83813)

CWE-ID: CWE-346 - Origin Validation Error

CVSSv4: 2.3 [CVSS:4.0/AV:A/AC:L/AT:P/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N]


The vulnerability allows forged DNS answers and DNS cache poisoning in applications using Twisted's DNS client, redirecting hostname resolution to attacker-chosen addresses. Successful exploitation can enable mail interception through forged MX or A records, server-side request forgery, or man-in-the-middle positioning against applications that trust the resolved address.

The vulnerability exists due to missing response source-address validation in twisted.names.dns.DNSDatagramProtocol.datagramReceived in src/twisted/names/dns.py. Responses are accepted for pending queries solely when their 16-bit transaction ID matches an entry in liveMessages; the supplied UDP source address is not compared with the queried server's address. The UDP socket is not connected to that server, so the kernel does not filter unrelated senders either. A remote attacker can send a forged DNS response from an unrelated address to the resolver's listening port and satisfy a pending query if the packet carries the correct transaction ID and arrives before the query completes or times out.

The transaction ID is generated using secure randomness, but its space is only 65,536 possibilities. The standard twisted.names.client.Resolver creates a new protocol instance and independently randomized source port for each query, then closes the socket when the query completes, requiring an off-path attacker to guess roughly 32 combined bits of port and transaction ID within the query timeout. Direct use of the public DNSDatagramProtocol class across multiple queries on one instance instead reuses the listening port; once that port is known, subsequent queries require guessing only the 16-bit transaction ID. An on-path attacker, an attacker sharing a broadcast domain or NAT with the resolver or DNS server, or another party able to observe or narrow the ephemeral port faces a reduced guessing barrier and no additional source-address check. The same acceptance logic affects createResolver and consumers of the standard resolver, including MX lookups in twisted.mail.


3) Allocation of Resources Without Limits or Throttling (CVE-ID: CVE-2026-115776)

CWE-ID: CWE-770 - Allocation of Resources Without Limits or Throttling

CVSSv4: 8.7 [CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N]


The vulnerability allows an unauthenticated remote client to exhaust the memory of a Twisted words IRC server and cause a denial of service for all users. A single connection can drive the entire single-threaded server process out of memory, dropping all connections and leaving the service unavailable until restarted. There is no confidentiality or integrity impact and no code execution.

The vulnerability exists due to unbounded accumulation of incomplete IRC lines in twisted.words.protocols.irc.IRC.dataReceived. Received data is concatenated with self.buffer and split at line feeds; the remaining incomplete line is retained without a maximum length. A remote attacker can open a single TCP connection to the IRC server and continuously send data containing no line feed, causing every chunk to remain buffered without completing a command. Buffering occurs before authentication or processing of PASS, NICK, or USER, so no credentials are required. The protocol has no line-length limit, overlength handler, or timeout to close this connection, and quadratic buffer copying accelerates resource exhaustion.

The affected component is Twisted's twisted.words IRC server, rather than its web server. The IRC class in twisted/words/protocols/irc.py derives directly from Protocol, not LineReceiver, and therefore does not inherit its line-length enforcement. The twisted.words.service.IRCUser subclass used by twistd words inherits the vulnerable method unchanged. In a measured test, 60 MB of line-feed-free input on one unauthenticated connection increased server resident memory from approximately 47 MB to 2966 MB without closing the connection or triggering a limit; the same volume of line-feed-terminated commands left memory usage flat.


4) Infinite loop (CVE-ID: CVE-2026-115774)

CWE-ID: CWE-835 - Loop with Unreachable Exit Condition ('Infinite Loop')

CVSSv4: 6.9 [CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N]


The vulnerability allows an authenticated remote client to cause a process-wide denial of service in Twisted's IMAP4 server with a single small SEARCH command. The resulting infinite loop consumes a CPU core and freezes the single-threaded reactor, stopping all other IMAP connections and services co-hosted on that reactor, including SMTP or POP3. There is no confidentiality or integrity impact and no code execution.

The vulnerability exists due to missing validation of negative inline literal sizes in twisted.mail.imap4.parseNestedParens. The parser converts the size with int() and advances its cursor using that value without rejecting a negative size. A value such as {-100} moves the cursor into negative indices; Python's negative-index slicing does not raise an exception, and the scanning loop cycles indefinitely while its exit condition remains unsatisfied. A remote attacker can log in with any valid account, select a mailbox, and submit a SEARCH command containing such a negative inline literal size to trigger the loop.

The affected component is twisted.mail.imap4.IMAP4Server. SEARCH reaches the parser through select_SEARCH and arg_searchkeys only in the selected state, making authentication and mailbox selection prerequisites. The _literalStringLimit guard covers the synchronizing-literal continuation path but not the vulnerable inline branch. Valid positive literal sizes complete normally, while non-numeric sizes produce a parse error. Parsing runs synchronously in the reactor thread, so connection timeouts cannot fire once the loop freezes the reactor.


5) Inconsistent interpretation of HTTP requests (CVE-ID: CVE-2026-115877)

CWE-ID: CWE-444 - Inconsistent Interpretation of HTTP Requests ('HTTP Request Smuggling')

CVSSv4: 6.3 [CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N]


The vulnerability allows HTTP request smuggling in Twisted Web when it is deployed behind a front-end proxy that accepts a bare carriage return (CR) or line feed (LF) as a header-line terminator. An attacker can bypass front-end access controls, poison a shared connection so that a later victim receives the response to an attacker-chosen request, and poison a cache. The vulnerability does not permit code execution.

The vulnerability exists due to incomplete header-value validation in twisted.web.http.HTTPChannel.headerReceived, which rejects NUL bytes but accepts bare CR and LF characters. A remote attacker can send a request through a front-end with the differing line-termination behavior, embedding a bare CR or LF followed by a Content-Length header inside another header's value and placing a second request after the header block. Twisted splits header lines only on CRLF, so it treats the embedded header as part of the preceding value, never recognizes its body length, and frames the first request with an empty body. The front-end instead recognizes the embedded header and treats the following bytes as the first request's body, while Twisted parses those bytes as a separate request. Both the bare CR and bare LF variants produce this disagreement.

In twisted/web/http.py, the header parser splits each header line at the first colon and strips spaces and tabs from the value, leaving embedded CR and LF characters intact. Because _maybeChooseTransferDecoder receives only the outer header name, it does not install a body decoder for the concealed Content-Length header. Header names and request lines already reject CR and LF; the validation gap is confined to header values, contrary to RFC 9110 section 5.5. For example, bytes intended by the front-end as the body of a request to /public can become a separate request to /admin in Twisted, generating an extra response that can desynchronize a shared connection. The request-smuggling exposure requires the front-end parsing discrepancy.


6) Allocation of Resources Without Limits or Throttling (CVE-ID: CVE-2026-115775)

CWE-ID: CWE-770 - Allocation of Resources Without Limits or Throttling

CVSSv4: 0 [CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:N/SI:N/SA:N]


The vulnerability allows an unauthenticated remote peer to exhaust server memory and cause denial of service in deployments that parse untrusted XML streams using Twisted's domish element stream, such as XMPP servers or components. A single stream can grow an in-memory element tree without bound until the operating system kills the server process. Per-element object overhead amplifies memory consumption relative to the traffic sent, allowing modest-bandwidth traffic or several concurrent streams to exhaust memory. There is no confidentiality or integrity impact and no code execution.

The vulnerability exists due to unrestricted allocation and retention of XML elements without limits on tree depth, child count, or unfinished document size. A remote attacker can connect to an endpoint using this XML stream stack, send an opening stream tag and a container element, then continuously send child elements without closing the container. Each child remains attached to the unfinished container, including children whose own end tags have arrived, so memory consumption continues to grow.

In src/twisted/words/xish/domish.py, ExpatElementStream._onStartElement appends each new element to the current element's children and descends into it without checking depth or child count. An element is emitted and dropped only when its end tag arrives while it sits directly beneath the document root; leaving that container open retains its entire subtree. The transport's XmlStream.dataReceived passes incoming bytes to self.stream.parse(data) without a size limit. In XMPP, this parsing occurs during negotiation before authentication, so credentials are not required.


7) Allocation of Resources Without Limits or Throttling (CVE-ID: CVE-2026-115778)

CWE-ID: CWE-770 - Allocation of Resources Without Limits or Throttling

CVSSv4: 8.7 [CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N]


The vulnerability allows an unauthenticated remote peer to exhaust server memory through a single connection to an exposed Twisted conch Telnet transport, causing denial of service. Unbounded memory growth can cause the operating system to kill the server process, disrupting every service it hosts. There is no confidentiality or integrity impact and no code execution.

The vulnerability exists due to an unbounded per-connection subnegotiation buffer in Telnet.dataReceived in src/twisted/conch/telnet.py. Receiving IAC SB enters the subnegotiation state and initializes a command list; each subsequent non-IAC byte is appended without a length check. The list persists across reads and is deleted only when IAC SE completes the subnegotiation. A remote attacker can connect to an endpoint exposing this transport, send IAC SB (0xFF 0xFA), and continuously stream non-0xFF bytes while withholding IAC SE (0xFF 0xF0), making the buffer grow for the life of the connection.

The affected surface includes exposed Twisted Telnet endpoints such as the manhole Telnet service. Option negotiation occurs before authentication, so no credentials are required. Negotiation bytes are consumed inside Telnet.dataReceived before application callbacks, preventing the application from imposing a buffer bound. Each byte is retained as a separate list element, amplifying memory consumption through per-byte overhead; a modest-bandwidth peer using one connection, or several such connections, can therefore drive the process to memory exhaustion.


Remediation

Install update from vendor's website.