CVEReports
Reports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Reports
  • Sitemap

Company

  • About
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Powered by Google Gemini & CVE Feed

|
•

CVE-2023-44487
CVSS 7.5|EPSS 94.40%

HTTP/2 Rapid Reset: How a Single TCP Connection Can Nuke a Server

Amit Schendel
Amit Schendel
Senior Security Researcher•October 10, 2023•11 min read
Active Exploitation
CISA KEV Listed

Executive Summary (TL;DR)

A design flaw in the HTTP/2 protocol allows an attacker to open and immediately cancel a massive number of data streams over a single connection. This forces the server to burn CPU and memory on useless setup/teardown work, leading to a complete Denial of Service. Because it's a protocol issue, almost everyone was vulnerable. It has been actively and massively exploited in the wild.

CVE-2023-44487, dubbed 'Rapid Reset,' is a protocol-level vulnerability in HTTP/2 that allows a single client to overwhelm and crash even the most powerful servers. By abusing the stream cancellation mechanism, an attacker can force a server to perform a massive amount of work setting up and tearing down communication streams, while the attacker expends almost no resources. This asymmetry creates a devastating Denial of Service vector that bypasses traditional rate-limiting defenses. The flaw isn't in a specific piece of software, but in the very design of the protocol, leading to a coordinated, internet-wide patching effort affecting nearly every modern web server, CDN, and load balancer.

HTTP/2: The Protocol We Were Promised

Let's take a trip back in time. HTTP/1.1 was the workhorse of the web for two decades, but it was getting creaky. It suffered from head-of-line blocking, meaning if one resource was slow to load, everything else had to wait in line behind it. It was like a single-lane road in a world that desperately needed a superhighway.

Enter HTTP/2, the shining knight in futuristic armor. It promised to fix everything with a magical concept called 'multiplexing.' Instead of one request-response pair at a time, you could have dozens, hundreds, even thousands of parallel conversations, called 'streams,' all happening over a single TCP connection. It was brilliant. Faster load times, less overhead, happier users. We all adopted it, patting ourselves on the back for being so modern and efficient.

The stream is the fundamental unit of HTTP/2. A client opens a stream to request a resource (an image, a CSS file), and the server uses that same stream to send it back. You can have streams for different resources all active at once, interleaved and prioritized. This is what gives HTTP/2 its power. The protocol also includes management frames to control these streams, including one called RST_STREAM.

The RST_STREAM frame is the protocol's 'never mind' button. It lets a client or server say, 'I don't need this stream anymore, please cancel it.' A browser might use it if a user navigates away from a page while large images are still downloading. It's a necessary feature for resource management. But as we're about to see, the road to hell is paved with good intentions, and this particular feature was a backdoor waiting to be kicked in.

A Protocol's Achilles' Heel: The RST_STREAM Frame

The vulnerability isn't a classic memory corruption bug or a logic flaw in a single product. It's far more insidious. It's an economic imbalance baked into the HTTP/2 specification itself. The core of the problem lies in the asymmetry of work between the client and the server when handling new streams.

When a client wants to start a new stream, it sends a HEADERS frame. Upon receiving this, the server has to do a fair bit of work. It needs to parse the headers, allocate memory for the stream's state, assign it a unique ID, and prepare to handle the request. This isn't free; it consumes CPU cycles and precious RAM. The server does all this in good faith, assuming the client actually wants something.

The RST_STREAM frame, however, throws a wrench in the works. A malicious client can send a HEADERS frame and then, in the very next packet, a RST_STREAM frame for that same stream. The server, dutifully following the protocol, has already done the setup work. It then has to perform more work to tear down the stream it just created. The client, on the other hand, has expended virtually zero resources. It just fired off two small packets and moved on.

Now, imagine this happening a few hundred thousand times per second. The client sends a massive volley of HEADERS frames, immediately followed by a volley of RST_STREAM frames. The server is caught in a Sisyphean nightmare. It's endlessly allocating and deallocating resources for streams that never even get used. Its request queue fills up, its CPU usage skyrockets to 100%, and its memory is devoured. The server grinds to a halt, unable to serve legitimate traffic. This is the Rapid Reset attack.

The Smoking Gun: A Tale of Two Implementations

To truly grasp the failure, let's look at how a naive server implementation might handle this. The context didn't give us a specific patch, but the problem is universal, so we can create a plausible scenario. Imagine a simplified server loop written in a language like Go.

Here's the 'before' picture. The code is clean, simple, and follows the spec. It reads a frame, and if it's a HEADERS frame, it dutifully calls createNewStream(). This function allocates memory and adds the stream to a global map. It's a synchronous, trusting model.

// BEFORE: A trusting, synchronous server loop
func handleConnection(conn net.Conn) {
    framer := http2.NewFramer(conn, conn)
    streamMap := make(map[uint32]*Stream)
 
    for {
        frame, err := framer.ReadFrame()
        if err != nil {
            // Handle error
            return
        }
 
        switch f := frame.(type) {
        case *http2.HeadersFrame:
            // Trust the client, create the stream immediately
            stream := createNewStream(f.StreamID)
            streamMap[f.StreamID] = stream
            go handleRequest(stream) // Process in background
 
        case *http2.RSTStreamFrame:
            // Client wants to cancel, so we clean up
            if stream, ok := streamMap[f.StreamID]; ok {
                stream.cancel()
                delete(streamMap, f.StreamID)
            }
        }
    }
}

This code is a ticking time bomb. An attacker can force createNewStream() to be called thousands of times, filling streamMap and spawning goroutines, only to have them all immediately torn down. The fix isn't a simple one-line change; it requires a fundamental shift in thinking. The server can no longer trust the client. It needs to enforce limits.

Here's the 'after' picture. The server now maintains a counter for pending streams and a limit. It only allocates the full stream object after it's sure the client isn't just spamming resets. It introduces rate-limiting.

// AFTER: A skeptical, rate-limiting server loop
const maxPendingResets = 100
const resetTimeWindow = 10 * time.Second
 
func handleConnection(conn net.Conn) {
    // ... (framer setup)
    recentResets := 0
    resetTimer := time.NewTicker(resetTimeWindow)
 
    go func() {
        <-resetTimer.C
        recentResets = 0 // Reset counter every window
    }()
 
    for {
        // ... (read frame)
        switch f := frame.(type) {
        case *http2.HeadersFrame:
            // Still create the stream, but be ready to kill the connection
            // ...
 
        case *http2.RSTStreamFrame:
            recentResets++
            if recentResets > maxPendingResets {
                log.Printf("Rapid Reset detected from %s. Terminating connection.", conn.RemoteAddr())
                // Send GOAWAY frame and close the connection
                framer.WriteGoAway(0, http2.ErrCodeEnhanceYourCalm, []byte("calm down"))
                conn.Close()
                return
            }
            // ... (cleanup stream)
        }
    }
}

This is the core of the mitigation. The server now keeps score. If a client acts suspiciously by resetting too many streams too quickly, the server doesn't just play along. It shows the client the door by terminating the entire connection. It's a bouncer for your server's resources.

Weaponizing the Reset: Your Server's Worst Nightmare

So, how does an attacker actually pull this off? It's disturbingly simple. You don't need a massive botnet (though it certainly helps). A single, well-connected machine can bring a powerful server to its knees. The beauty of the attack, from the adversary's perspective, is its efficiency.

The attack script first establishes a standard TCP connection to the target server and performs the HTTP/2 preface handshake. This makes the connection look perfectly legitimate. Now, the attacker has an open channel, ready for multiplexing. The server is sitting there, waiting for stream requests.

Then, the core attack loop begins. It's brutally effective:

  1. Construct a HEADERS frame for a new stream (e.g., stream ID 1). This can be a minimal request, like GET /.
  2. Construct a RST_STREAM frame for that same stream ID (stream ID 1).
  3. Shove both frames into the TCP socket buffer, one right after the other.
  4. Increment the stream ID (to 3, since stream IDs must be odd for clients) and repeat.

Here's what that looks like in pseudo-code:

# Conceptual PoC for CVE-2023-44487
sock = connect_and_handshake('target.com', 443)
stream_id = 1
 
while True:
    # Create a request for a new stream
    headers_frame = create_headers_frame(stream_id, path='/')
    
    # Create a frame to immediately cancel it
    reset_frame = create_rst_stream_frame(stream_id)
    
    # Send them back-to-back
    try:
        sock.send(headers_frame + reset_frame)
    except SocketError:
        print("Server likely died. Reconnecting...")
        sock = connect_and_handshake('target.com', 443)
        stream_id = 1 # Reset stream ID for new connection
        continue
 
    # HTTP/2 stream IDs from clients must be odd numbers
    stream_id += 2 

This loop can be executed tens of thousands of times per second. The attacker isn't waiting for a response. They are fire-and-forgetting, stuffing the server's TCP receive buffer with an endless list of chores. Because this all happens over one or a few TCP connections, it flies under the radar of traditional DoS defenses that look for SYN floods or massive numbers of connections from different IPs. It's a stealthy, resource-amplifying attack that turns the server's own efficiency against it.

The Domino Effect: When the Web Goes Dark

The real-world impact of this vulnerability cannot be overstated. This wasn't some niche bug in an obscure library; it was a fundamental flaw in the plumbing of the modern internet. When the coordinated disclosure happened on October 10, 2023, it became clear that almost every major web service was, at some point, vulnerable.

The consequences of a successful Rapid Reset attack are catastrophic for the target. It's not just a slowdown; it's a complete lights-out scenario. Server CPUs are pegged at 100% as they frantically try to keep up with the endless stream setup and teardown cycle. Memory usage balloons as state is allocated for hundreds of thousands of phantom streams. Eventually, the operating system's scheduler can't keep up, and the server process becomes unresponsive, unable to even serve a simple health check, let alone handle legitimate user traffic.

This leads to cascading failures. If the target is a load balancer, everything behind it becomes unreachable. If it's a critical API endpoint, entire applications that depend on it will fail. The attacks observed in the wild were record-breaking. Cloudflare reported mitigating attacks that peaked at over 201 million requests per second. Google reported similar attacks of an unprecedented scale. These weren't script kiddies; this was a weaponized exploit used in massive DDoS campaigns.

Because the vulnerability is at the protocol level, the blast radius was enormous. It affected Nginx, Apache HTTP Server, Microsoft IIS, and countless other web servers. It hit CDNs, cloud providers, and enterprise-grade hardware load balancers. Any developer who built a service using a standard HTTP/2 library was likely vulnerable. It was a stark reminder that even the most foundational technologies can harbor critical flaws, and that complexity often hides the most dangerous secrets.

Stopping the Bleeding: A Band-Aid on a Protocol Wound

So, how do you defend against an attack that abuses the very rules of the protocol? You start by changing the rules of engagement. The fixes deployed by vendors and open-source projects are essentially about teaching servers to be more cynical and less trusting.

The most effective mitigation is to apply the patches provided by your software vendors. Whether you're running Nginx, Apache, Node.js, or using a library like nghttp2, updates are available. These patches introduce connection-level rate-limiting specifically for stream resets. A patched server now keeps a running tally of how many streams a client has cancelled in a short period. If that number exceeds a reasonable threshold, the server assumes the client is malicious.

Instead of continuing to play the attacker's game, the server takes decisive action. It sends a GOAWAY frame, which is the HTTP/2 equivalent of 'get out and don't come back.' This frame tells the client the connection is being terminated. The server might use the error code ENHANCE_YOUR_CALM, a wonderfully passive-aggressive way of telling an attacker's script to back off. After sending the GOAWAY frame, the server closes the TCP connection, neutralizing the threat from that client.

For those who couldn't patch immediately, other workarounds exist. Network-level defenses at the edge (like WAFs or Application Delivery Controllers) can be configured to monitor HTTP/2 connections for this specific pattern of rapid resets and terminate them before they reach the origin servers. In a worst-case scenario, administrators could disable HTTP/2 entirely and fall back to HTTP/1.1, sacrificing performance for availability. This is a drastic step, but it highlights the severity of the vulnerability. The long-term fix might require revisions to the HTTP/2 protocol itself, but for now, these server-side heuristics are the dam holding back the flood.

Technical Appendix

CVSS Score
7.5/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
EPSS Probability
94.40%
Top 6% most exploited

Affected Systems

Any web server, CDN, load balancer, or application implementing the HTTP/2 protocol.

Affected Versions Detail

ProductAffected VersionsFixed Version
Various HTTP/2 Implementations
Multiple Vendors
All unpatched versions-
AttributeDetail
CWE IDCWE-400
CWE NameUncontrolled Resource Consumption
Attack VectorNetwork
CVSS Score7.5 (High)
EPSS Score0.944 (94.4%)
ImpactDenial of Service
Exploit StatusActive Exploitation
KEV StatusListed in CISA KEV Catalog

MITRE ATT&CK Mapping

MITRE ATT&CK Mapping

T1498Network Denial of Service
Impact
CWE-400
Uncontrolled Resource Consumption

The software does not properly control the allocation and maintenance of a limited resource, such as memory, file handles, or network connections. An attacker can exploit this by crafting requests that trigger excessive resource allocation, eventually leading to a denial of service when the resource is exhausted.

Exploit Resources

Known Exploits & Detection

GitHubProof-of-concept exploit script for demonstrating the HTTP/2 Rapid Reset vulnerability.
GitHubAnother PoC implementation in Go for testing server resilience against CVE-2023-44487.

Vulnerability Timeline

Vulnerability Timeline

Initial large-scale exploitation campaigns begin, targeting major infrastructure providers.
2023-08-25
Coordinated public disclosure of the vulnerability by multiple vendors.
2023-10-10
CVE-2023-44487 is officially published and added to CISA's KEV catalog.
2023-10-10
Major open-source projects and vendors have patches widely available.
2023-10-11

References & Sources

  • [1]NVD - CVE-2023-44487
  • [2]Cloudflare: Technical Deep Dive on the HTTP/2 Rapid Reset DDoS Attack
  • [3]CISA Alert (AA23-284A): HTTP/2 Rapid Reset Vulnerability
  • [4]Google Cloud: Mitigating the largest DDoS attack in history

Subscribe to updates

Get the latest CVE analysis reports delivered to your inbox.

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.