Vulnerabilities

7 min readUpdated

CVE-2023-44487: the HTTP/2 Rapid Reset attack

Quick answer

CVE-2023-44487, known as HTTP/2 Rapid Reset, is a protocol-level denial-of-service technique disclosed on 10 October 2023. A client opens an HTTP/2 stream with a request and immediately sends RST_STREAM to cancel it. Cancelled streams stop counting toward the concurrency limit, so one connection can keep the server busy far faster than it can shed the work. It powered record application-layer DDoS attacks, including 201 million and 398 million requests per second, and is listed in the CISA KEV catalogue.

At a glance

high severity
Identifier
CVE-2023-44487
Also known as
HTTP/2 Rapid Reset
Product
HTTP/2 protocol — most server and proxy implementations
Affected
nginx 1.9.5 – 1.25.2 (mainly where keepalive_requests was raised far above the default); Go net/http before 1.21.3 / 1.20.10; golang.org/x/net/http2 before 0.17.0; Envoy before 1.27.1 / 1.26.5 / 1.25.10 / 1.24.10; Node.js (nghttp2) and many others — see vendor advisories
Fixed in
nginx 1.25.3; NGINX Plus R29p1 / R30p1; Go 1.21.3 / 1.20.10; x/net 0.17.0; Envoy 1.27.1 / 1.26.5 / 1.25.10 / 1.24.10; Node.js 18.18.2 / 20.8.1; nghttp2 1.57.0
CVSS
7.5 (CVSS 3.1)
Disclosed
Known exploited (CISA KEV)
Yes

Exploited in the wild since August 2023. Listed in CISA KEV (added 10 October 2023). Patched across the ecosystem.

01What is HTTP/2 Rapid Reset?

CVE-2023-44487 is a denial-of-service weakness in the HTTP/2 protocol itself, not a bug in one product. It was disclosed on 10 October 2023 by Cloudflare, Google and AWS after being exploited in the wild from August 2023. CISA added it to the Known Exploited Vulnerabilities catalogue the same day.

The mechanism is simple. HTTP/2 lets a client cancel a request by sending an RST_STREAM frame. The attacker opens a stream with a complete request and immediately cancels it, over and over. Each cancellation frees a slot for a new stream instantly, so the request rate on one connection is bounded only by the attacker's bandwidth — not by the round-trip time and not by the server's concurrency limit.

Because it is an application-layer flood that consumes CPU rather than bandwidth, it belongs to the same family as a classic HTTP flood but is far more efficient. For the wider picture of volumetric versus application attacks, see what a DDoS attack is.

02Why did it break records?

HTTP/2 multiplexes many streams over one connection and caps how many can be active at once using SETTINGS_MAX_CONCURRENT_STREAMS, typically 100 or 128. In a normal flood, that cap plus the round-trip time limits how many requests a client can keep in flight. Rapid Reset removes both limits.

When a stream is reset it immediately becomes closed, and closed streams do not count toward the concurrency cap. So the attacker never exceeds the advertised limit, yet keeps the server perpetually busy setting up and tearing down streams: allocating stream state, decompressing headers, parsing the request, and often proxying it to a backend before the cancellation is even processed. The client pays almost nothing; the server pays for every request. That asymmetry is what made it an amplifier at the application layer.

ReporterPeak rateContext
Cloudflare201 million req/sNearly 3x Cloudflare's previous record of 71M req/s; botnet of about 20,000 machines
Google398 million req/sLargest reported Layer 7 attack at the time
AWS155 million req/sA dozen-plus events over 28–29 August 2023

03How does the attack work, step by step?

At a conceptual level, the loop is: open a stream with a full request, then cancel it before the response comes back. There are two documented variants beyond the basic form, which is why counting client resets alone was not a complete defence.

The basic form abuses request cancellation, a legitimate feature browsers use when a user navigates away. The non-cancelling variant does not reset anything; it simply opens more streams than allowed, which is why servers also had to close connections that exceed the stream limit rather than only limiting resets.

  • Basic Rapid Reset: send HEADERS (with END_STREAM) then an immediate RST_STREAM, repeatedly
  • Batched variant: open a large batch of streams, wait briefly, cancel them all, then open another batch
  • Non-cancelling variant: open more concurrent streams than the server advertised, without resetting at all
  • In every case the server does real work for requests that are never completed from the client's side

04Which servers patched how?

Because it is a protocol weakness, almost every HTTP/2 implementation shipped a fix within days or weeks of the 10 October 2023 disclosure. The fixes share a theme: account for streams that are reset or cancelled, and close the whole connection when a client's behaviour looks abusive, rather than trying to block individual requests.

F5 noted that nginx with default settings was largely protected already, because the default keepalive_requests limit of 1,000 caps how many requests a single connection can make; the patch tightened stream-rate handling further. The lesson across vendors is that the fix is operational, not a single magic value; the other nginx limits that matter in a flood are covered in nginx DDoS protection.

ImplementationFixed version(s)Approach
nginx1.25.3; NGINX Plus R29p1 / R30p1Limits new streams per event loop to 2x http2_max_concurrent_streams; keep keepalive_requests at its default
Go net/http, golang.org/x/net/http2go1.21.3, go1.20.10; x/net 0.17.0 (CVE-2023-39325)Caps concurrent handler goroutines; queues and then drops connections with oversized queues
Envoy1.27.1, 1.26.5, 1.25.10, 1.24.10Budget on premature resets per connection (default 500) before disconnecting
Node.js (nghttp2)18.18.2, 20.8.1; nghttp2 1.57.0Bounds rapid stream create/cancel cycles
Apache Tomcat8.5.94, 9.0.81, 10.1.14, 11.0.0-M12Treats excess stream churn as abuse
Apache httpd2.4.58 (related CVE-2023-45802)Reclaims stream memory promptly on RST
Netty / Jettynetty 4.1.100.Final; jetty 9.4.53 / 10.0.17 / 11.0.17 / 12.0.2Reset accounting and connection teardown

05What stops it, and what does not?

The vendor guidance converged on one principle: you cannot usefully block individual requests, because by the time you decide a request is abusive the stream is already closed. The whole TCP connection has to be torn down when abuse is detected.

  • Track per-connection statistics: a connection with many requests of which a large share are cancelled is a strong candidate for teardown (Google's example: more than 100 requests with over 50% cancelled)
  • Close connections that exceed the stream limit, to cover the non-cancelling variant
  • Keep server stream limits and keepalive request caps at sane defaults
  • Apply rate limiting and connection limits as supporting controls, not as the sole defence
  • Do not rely on GOAWAY alone — it does not stop inbound requests fast enough

06How do you detect it in logs?

The fingerprint is a high rate of requests that never complete normally, concentrated on a small number of connections, with CPU high but bandwidth ordinary. In nginx access logs, HTTP/2 requests the client cancelled typically surface as status 499 (client closed the request), which Cloudflare also observed during the attacks. A per-connection count of 499s is a useful triage signal.

Treat the threshold below as illustrative and tune it to your traffic; a few cancellations per connection are normal browser behaviour. Envoy's advisory describes the same signal as elevated downstream_rq_http2_total without a substantial rise in downstream_cx_active. For the step-by-step response during an incident, see how to stop a DDoS attack.

Counting cancelled HTTP/2 requests per connection (nginx access log)
# log format must include $connection and $server_protocol, e.g.:
# log_format h2 '$remote_addr conn=$connection $server_protocol $status "$request"';
# fields: $1 address, $2 conn=N, $3 protocol, $4 status

# connections with more than 100 cancelled HTTP/2 requests
awk '$3=="HTTP/2.0" && $4==499 {n[$1" "$2]++}
     END {for (k in n) if (n[k]>100) print n[k], k}' access.log

Questions

Frequently asked questions

Both, in effect. It is a weakness in the HTTP/2 protocol's stream lifecycle that many implementations shared, so it received one CVE even though the fix differed per product. It is best understood as a denial-of-service technique that works against any HTTP/2 server that did real work for streams a client cancels before completion.

Most HTTP/2 implementations were affected to some degree, because the weakness is in the protocol. Some, like a default nginx, were partly protected by existing keepalive limits. The practical answer is to run a version released after mid-October 2023 for your server, since nearly every vendor shipped a fix within days of disclosure.

Not on its own. Rate limiting helps, but the defining fix is connection-level: track how many streams a connection opens and cancels, and tear down the whole connection when the pattern is abusive. Blocking individual requests does not work, because the stream is already closed by the time you assess it. Rate limiting is a supporting control.

They set records for application-layer attacks. Cloudflare measured a peak of 201 million requests per second, nearly three times its own previous record, from a botnet of roughly 20,000 machines. Google reported 398 million requests per second, and AWS mitigated events peaking over 155 million requests per second during 28–29 August 2023.

Yes. CISA added HTTP/2 Rapid Reset to the Known Exploited Vulnerabilities catalogue on 10 October 2023, the day of public disclosure, because it had already been exploited in the wild since August 2023. US federal agencies were directed to apply vendor mitigations, and the listing signals that patching should be treated as urgent.

Sources

Sources and verification

The log_format line loaded into nginx 1.22.1 with nginx -t, and the per-connection 499 count run with mawk and GNU awk 5.2.1 against a sample access log, on Debian 12, October 2026.

  1. 01NVD — CVE-2023-44487 · NVD
  2. 02CISA alert — HTTP/2 Rapid Reset, CVE-2023-44487 · CISA
  3. 03Cloudflare — technical breakdown of the HTTP/2 Rapid Reset DDoS attack · Cloudflare
  4. 04Google Cloud — how the novel HTTP/2 Rapid Reset DDoS attack works · Google Cloud
  5. 05F5 NGINX — HTTP/2 Rapid Reset attack impacting NGINX products · F5 NGINX
  6. 06Go vulnerability report GO-2023-2102 (CVE-2023-39325) · Go
  7. 07Envoy security advisory GHSA-jhv4-f7mr-xx76 · Envoy
  8. 08AWS — How AWS protects customers from DDoS events · AWS Security Blog
  9. 09Apache Tomcat 9 security vulnerabilities · Apache Tomcat
  10. 10Apache HTTP Server 2.4 vulnerabilities (CVE-2023-45802) · Apache HTTP Server

Last updated