CVE-2026-77791

Denial of Service
Affects
tomcat-websocket
in
Apache Tomcat
No items found.
Versions
>=8.5.88 <=8.5.100, >=9.0.74 <9.0.122, >=10.1.8 <10.1.60, >=11.0.0-M5 <11.0.26

Patch Available.

Exclamation circle icon
Patch Available

This Vulnerability has been fixed in the Never-Ending Support (NES) version offered by HeroDevs.

Overview

Apache Tomcat is an open-source implementation of the Jakarta Servlet, Jakarta Pages, Jakarta Expression Language, Jakarta WebSocket, Jakarta Annotations, and Jakarta Authentication specifications. It serves Java web applications either as a standalone servlet container and HTTP server or embedded inside an application through the tomcat-embed-core artifact. It also implements the Jakarta WebSocket API; the server-side WebSocket runtime ships in the org.apache.tomcat:tomcat-websocket artifact (and org.apache.tomcat.embed:tomcat-embed-websocket for embedded use), which is where this issue lives.

A Denial of Service (DoS) vulnerability (CVE-2026-77791) has been identified in the Apache Tomcat WebSocket implementation, which allows a remote peer to pin a container thread in a busy wait while the container sends a WebSocket close message. The thread spins without ever blocking, burning CPU for as long as the peer keeps the pending write outstanding, so a small number of connections can consume a disproportionate share of available processing capacity.

Per OWASP: The Denial of Service (DoS) attack is focused on making a resource (site, application, server) unavailable for the purpose it was designed. There are many ways to make a service unavailable for legitimate users by manipulating network packets, programming, logical, or resources handling vulnerabilities, among others.

This issue affects the Jakarta WebSocket implementation of Apache Tomcat, including the End-of-Life 8.5.x line.

Module Info

Vulnerability Info

This High-severity vulnerability is found in the org.apache.tomcat:tomcat-websocket package in the 8.5.x line of Apache Tomcat, in the org.apache.tomcat.websocket.server.WsRemoteEndpointImplServer endpoint used to write WebSocket frames on the server side.

Tomcat serializes WebSocket message writes with a single-permit semaphore, messagePartInProgress. A permit is taken before a message part is written and released when that write completes, so a message whose write has not yet drained to the network holds the permit for as long as the peer declines to read. Separately, WsRemoteEndpointImplServer carries special handling for one scenario: a close message that has to be sent from a thread that is already processing a socket event and therefore already holds the socket wrapper lock. Waiting on the semaphore while holding that lock would dead-lock the connection, so instead of waiting the container releases the processor and the socket lock, gives other threads a chance to run, then re-takes both and tries again:

if (opCode == Constants.OPCODE_CLOSE && reentrantLock.isHeldByCurrentThread()) {
    int socketWrapperLockCount = reentrantLock.getHoldCount();

    while (!messagePartInProgress.tryAcquire()) {
        if (timeoutExpiry < System.currentTimeMillis()) {
            return false;
        }
        try {
            // Release control of the processor
            socketWrapper.setCurrentProcessor(connection);
            // Release the per socket lock(s)
            for (int i = 0; i < socketWrapperLockCount; i++) {
                socketWrapper.getLock().unlock();
            }
            // Provide opportunity for another thread to obtain the socketWrapper lock
            Thread.yield();
        } finally {
            // Re-obtain the per socket lock(s)
            for (int i = 0; i < socketWrapperLockCount; i++) {
                socketWrapper.getLock().lock();
            }
            // Re-take control of the processor
            socketWrapper.takeCurrentProcessor();
        }
    }

    return true;
}

The retry loop never blocks. tryAcquire() returns immediately, and the only pause between attempts is Thread.yield(), which is a scheduling hint rather than a wait: on an otherwise idle core it returns almost at once. Each iteration also performs real work, unlocking and re-locking the socket wrapper lock and handing the processor back and forth, so the loop is not merely idling but repeatedly touching contended state. The loop exits only when the permit is finally free or when the send timeout expires, which defaults to 20 seconds for blocking sends.

The condition that keeps the permit held is controlled by the remote peer. A client that opens a WebSocket connection, gets the application to write a message, and then stops reading from the socket leaves that write pending and the permit taken. When the client then sends a close frame, the container thread that processes it enters the branch above and spins at full speed until the timeout elapses. Because the trigger is a pair of ordinary WebSocket frames and a stalled read, an unauthenticated remote peer can repeat it across connections and saturate CPU on the server, degrading or denying service to legitimate users.

Mitigation

Only recent versions of Apache Tomcat receive community support. Older lines are End-of-Life and will not receive public updates to address this issue. For more information, see here.

Users of the affected components should apply one of the following mitigations:

  • Upgrade to a patched version of Apache Tomcat.
  • Leverage a commercial support partner like HeroDevs for post-EOL security support.
Vulnerability Details
Severity
Level
CVSS Assessment
Low
>=0 <4
Medium
>=4 <6
High
>=6 <8
Critical
>=8 <10
High
ID
CVE-2026-77791
PROJECT Affected
tomcat-websocket
Versions Affected
>=8.5.88 <=8.5.100, >=9.0.74 <9.0.122, >=10.1.8 <10.1.60, >=11.0.0-M5 <11.0.26
NES Versions Affected
Published date
September 23, 2026
≈ Fix date
September 25, 2026
Category
Denial of Service
Vex Document
Download VEXHow do I use it?
Sign up for the latest vulnerability alerts fixed in
NES for Apache Tomcat
Rss feed icon
Subscribe via RSS
or

By submitting the form I acknowledge receipt of our Privacy Policy.

Thanks for signing up for our Newsletter! We look forward to connecting with you.
Oops! Something went wrong while submitting the form.