TLP:CLEAR

CVE-2026-23918 — Apache mod_http2
STREAM_CLOSED Rapid Reset

A coordinated fleet of scanning nodes probing for Apache mod_http2 servers vulnerable to a novel variant of the HTTP/2 Rapid Reset attack, using RST_STREAM(STREAM_CLOSED) instead of the CANCEL code used by CVE-2023-44487.

Published 2026-06-24 Source Distributed SSH/Telnet Honeypot Fleet Confidence High Classification Active Campaign

01 Executive summary

Four IP addresses, each on a different abuse-tolerant hosting provider, spent five days probing our honeypot fleet with browser traffic that looked completely legitimate down to the TLS fingerprint. What gave them away was a single byte in the HTTP/2 RST_STREAM error code, one that slips past the rate-limiting Apache shipped after the 2023 Rapid Reset attacks. No payloads were dropped, this is reconnaissance, and as of this writing it is still running.

4
Distinct scanner IPs
236
Sessions opened
391
RST_STREAM frames sent
100%
RSTs as STREAM_CLOSED
5
Honeypot nodes hit
0
Samples dropped

Between 2026-06-19 and 2026-06-23, the cowrAI honeypot fleet recorded four distinct source IPs conducting HTTP/2 vulnerability scanning consistent with CVE-2026-23918, an Apache mod_http2 flaw affecting stream state management. Each scanner sends bursts of 8–9 concurrent HTTP/2 connections, immediately issuing RST_STREAM frames with error code STREAM_CLOSED (0x5), a code distinct from the CANCEL (0x8) used by the 2023-era Rapid Reset attacks. No payloads were delivered; the HEADERS frames that do get sent are ordinary secret/config-exposure probes (.env, .git/HEAD, docker-compose*.yml — see §07) riding over HTTP/2, torn down with STREAM_CLOSED once the scanner is done with each stream.

A separate, concurrent campaign using RST_STREAM(CANCEL) (CVE-2023-44487) was observed from three additional IPs (Tencent Cloud, DigitalOcean). These are distinct from CVE-2026-23918 and documented in the IOC table for completeness.

02 Threat actor profile

No attribution to a named group. Infrastructure profile is consistent with a commercial vulnerability scanner or automated exploit kit renting nodes from abuse-tolerant hosting providers. No overlap with known APT infrastructure identified.

Infrastructure characteristics

IPASN / OrgCountryRoleCVE Family
185.65.135.182 AS39351 31173 Services AB SE Blaster CVE-2026-23918
103.81.231.93 AS203020 HostRoyale Technologies US Blaster CVE-2026-23918
146.70.201.108 AS9009 M247 Europe SRL JP Blaster CVE-2026-23918
154.47.29.11 AS212238 Datacamp Limited HR Blaster CVE-2026-23918
152.42.217.112 AS14061 DigitalOcean SG Scanner CVE-2023-44487
129.226.83.92 AS132203 Tencent Cloud SG Scanner CVE-2023-44487
43.128.73.4 AS132203 Tencent Cloud SG Scanner CVE-2023-44487

All CVE-2026-23918 nodes use abuse-tolerant hosting (31173 Services AB, HostRoyale, M247, Datacamp/Datapacket), a pattern consistent with rented scan infrastructure that prioritises network diversity over persistent IP identity. The CVE-2023-44487 nodes use mainstream cloud (DigitalOcean, Tencent) suggesting compromised instances or a separate operator with different opsec posture.

03 Infrastructure diagram

┌───────────────────────────────────────────────────────────────────┐ │ CVE-2026-23918 Scan Infrastructure │ └───────────────────────────────────────────────────────────────────┘ [185.65.135.182] AS39351 (SE) ──┐ [103.81.231.93 ] AS203020 (US) ─┤ [146.70.201.108] AS9009 (JP) ─┤──▶ Apache mod_http2 targets [154.47.29.11 ] AS212238 (HR) ─┘ (port 443 / TLS) observed fleet targets: five VPS-hosted honeypot sensors across provider regions Per-scan session pattern (8-9 concurrent connections): Scanner ──[TLS ClientHello]──▶ Target Scanner ──[HTTP/2 Preface ]──▶ Target Scanner ──[HEADERS frm #1]──▶ Target ← stream ID 1 opened Scanner ──[HEADERS frm #2]──▶ Target ← stream ID 3 opened (concurrent) ⋮ ⋮ Scanner ──[RST_STREAM 0x5 ]──▶ Target ← STREAM_CLOSED error, NOT CANCEL Scanner ──[RST_STREAM 0x5 ]──▶ Target ⋮ ⋮ (burst: 75–140 RSTs per IP) Scanner ──[session teardown]──▶ Target "Hero" sessions (1-2 per wave): many HEADERS + many RSTs "Filler" sessions (6-7 per wave): 1 HEADERS + 1 RST (hold-open, probe timing)

04 Technical analysis

CVE-2026-23918 vs CVE-2023-44487 — error code distinction

The 2023 HTTP/2 Rapid Reset attack (CVE-2023-44487) established a pattern: open a stream (HEADERS frame), then immediately cancel it (RST_STREAM with error code CANCEL = 0x8) before the server processes the request. Apache patched this path with rate-limiting on CANCEL RSTs in mod_http2.

CVE-2026-23918 uses STREAM_CLOSED (0x5) instead. Per RFC 9113, STREAM_CLOSED indicates "the stream is no longer open." Sending this as a client RST, before the server has responded, places mod_http2 into an ambiguous state: the stream object was allocated on receipt of HEADERS, but the client is now telling the server the stream is already closed from the client's perspective. This bypasses the CANCEL rate-limit codepath and targets a distinct branch of the stream state machine, likely triggering resource exhaustion or a use-after-free in stream cleanup.

PropertyCVE-2023-44487 (Rapid Reset)CVE-2026-23918 (STREAM_CLOSED)
RST error code0x8 CANCEL0x5 STREAM_CLOSED
Patched rate-limit bypassNo — rate-limitedYes — different code path
Attack vectorResource exhaustion (CPU)State confusion + potential UAF
Concurrent sessionsMany8–9 per wave (lower profile)
First seen in fleet2026-06-19

Browser UA rotation (anti-fingerprint)

CVE-2026-23918 sessions present realistic browser fingerprints with matching User-Agent and sec-ch-ua headers. Across all four scanner IPs we observed five distinct UA profiles, not three — including a Windows/Edge profile that is the single most common UA on two of the four IPs:

ProfileUser-Agentsec-ch-uaSeen on
Mac Chrome 120 Mozilla/5.0 (Macintosh…) Chrome/120.0.0.0 "Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120" 154.47.29.11 (20×)
Mac Chrome 124 Mozilla/5.0 (Macintosh…) Chrome/124.0.0.0 (not captured in this profile's sessions) 185.65.135.182 (22×), 103.81.231.93 (67×), 146.70.201.108 (15×)
Mac Chrome 131 Mozilla/5.0 (Macintosh…) Chrome/131.0.0.0 "Google Chrome";v="131", "Chromium";v="131", "Not_A Brand";v="24" all 4 IPs (89× combined)
Windows 10 Edge 101 Mozilla/5.0 (Windows NT 10.0; Win64; x64)… Chrome/101.0.4951.64 Edg/101.0.1210.47 (not captured in this profile's sessions) 185.65.135.182 (22×), 146.70.201.108 (44× — its most common UA)
Mac Safari 18 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Version/18.0 Safari/605.1.15 (absent — Safari does not send sec-ch-ua) 146.70.201.108 (1×), 154.47.29.11 (3×)

The macOS 10_15_7 (Catalina) platform string is common but is not a fixed anchor across all profiles — the Windows 10/Edge 101 UA accounts for the majority of requests from 146.70.201.108 and a third of requests from 185.65.135.182, so platform string alone is not a reliable discriminator for this campaign.

Scan wave pattern

Each scanner operates in waves: 8–9 connections open concurrently, all originating from a single source port per session. Within each wave, 1–2 "hero" connections send dozens of HEADERS+RST pairs while the remaining connections hold open (1 HEADERS, 1 RST each), likely testing server-side concurrency limits alongside the RST error path.

Wave timing (154.47.29.11 example — 118 seconds total, times UTC):
22:05:26.964  Wave start (single probe session)
22:05:42.560  8 concurrent sessions open simultaneously (incl. "hero" session 827c9e39955d)
22:05:48.975  1 follow-up session
22:05:58.187  8 concurrent sessions (second full burst)
22:06:04.938  1 follow-up session
22:06:20.537  8 concurrent sessions (third full burst)
22:06:26.946  1 follow-up session
22:06:36.156  8 concurrent sessions (fourth full burst)
22:06:49.938  1 follow-up session
22:07:09.877  8 concurrent sessions (fifth full burst)
22:07:10.265  1 closing session
22:07:24.589  All sessions closed (46 sessions total)

05 MITRE ATT&CK mapping

IDTechniqueEvidence
T1595.001 Active Scanning: Scanning IP Blocks Multiple scanner IPs hitting different honeypot nodes across the fleet
T1595.002 Active Scanning: Vulnerability Scanning RST_STREAM(STREAM_CLOSED) pattern targets specific mod_http2 code path
T1036 Masquerading Rotating 5 legitimate browser UA profiles (Mac Chrome 120/124/131, Windows Edge 101, Safari 18) with matching sec-ch-ua where applicable
T1583.003 Acquire Infrastructure: Virtual Private Server All nodes on abuse-tolerant VPS providers (Datacamp, M247, HostRoyale, 31173)
T1499.003 Endpoint DoS: Application Exhaustion Flood High-volume HEADERS+RST bursts targeting mod_http2 stream resource allocation

06 Campaign timeline

2026-06-19 19:31 UTC
First observed. 185.65.135.182 (AS39351 31173 Services AB, SE) conducts 54 sessions against one VPS-hosted honeypot sensor — 87 STREAM_CLOSED RSTs. First detection of CVE-2026-23918 pattern in fleet.
2026-06-20 21:36 UTC
Second node active. 103.81.231.93 (AS203020 HostRoyale, US) conducts 52 sessions against one VPS-hosted honeypot sensor — 89 STREAM_CLOSED RSTs. Scan completes in ~2 minutes.
2026-06-21 07:08–19:26 UTC
Third node, two targets. 146.70.201.108 (AS9009 M247, JP) hits two VPS-hosted honeypot sensors across provider regions — 84 sessions, 140 RSTs. Longest campaign duration of any single IP.
2026-06-23 22:05–22:07 UTC
Fourth node, triggering this brief. 154.47.29.11 (AS212238 Datacamp, HR) conducts 46 sessions against one additional VPS-hosted honeypot sensor — 75 STREAM_CLOSED RSTs. Session 827c9e39955d flagged as highest-RST session (10 RSTs).
2026-06-23 (ongoing)
Campaign still active. No cessation observed. New nodes likely being rotated in.

07 Captured HTTP/2 frames & headers

Raw headers captured by apachelure from session 827c9e39955d (154.47.29.11). Timestamps below are UTC. apachelure captures full HEADERS frames including the :method, :path, and :authority pseudo-headers — see "Requested paths" below for what these scanners were actually probing for.

--- HTTP/2 Frame Sequence (representative session 827c9e39955d) ---

[22:05:42.567] apache.h2_preface        ← client magic received
[22:05:42.567] apache.h2_frame          ← SETTINGS frame
[22:05:42.568] header_captured    sec-ch-ua: "Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"
[22:05:42.575] apache.h2_frame          ← HEADERS, stream 3: GET :authority= :path=/docker-compose.yml
                                            user-agent: Mozilla/5.0 (Macintosh…) Chrome/120.0.0.0 Safari/537.36
[22:05:42.576] apache.h2_frame          ← HEADERS, stream 5: GET :path=/docker-compose.yaml
[22:05:43.567] apache.h2_rst_stream     stream 1, STREAM_CLOSED (0x5) — no HEADERS ever sent on this stream
[22:05:43.568] apache.h2_frame          ← HEADERS, stream 7: GET :path=/docker-compose.prod.yml
  ⋮  (13× HEADERS total — mostly GET requests for .env / .git / docker-compose paths —
      interleaved with 10× RST_STREAM, all STREAM_CLOSED, targeting a mix of streams that
      did and did not carry a HEADERS frame)
[22:05:57.572] apache.h2_session_end    ← session closed

--- All RST_STREAM errors observed across campaign ---

apache:h2_rst_error:STREAM_CLOSED   391  (100% of CVE-2026-23918 RSTs)

Requested paths

Across the 4 CVE-2026-23918 IPs, apachelure captured 283 HTTP/2 requests spanning 38 distinct paths. The request pattern is a standard secrets/config-exposure sweep — .env variants, .git/HEAD, docker-compose*.yml — plus at least one known RCE probe (/_ignition/execute-solution, the Laravel Ignition deserialization RCE path). This is evidence the actors are not fuzzing the HTTP/2 stream state machine blind — they are running an ordinary web recon scanner over HTTP/2 and tearing down each stream with RST_STREAM(STREAM_CLOSED) once done with it.

PathRequests
/17
/graphql15
/.env.backup14
/backend/.env14
/.env.dev14
/api/.env12
/.env.production12
/.git/HEAD11
/.env.local11
/docker-compose.yml10

08 Indicators of compromise

CVE-2026-23918 scanner IPs

IPASNCountrySessionsRSTsFirst Seen
185.65.135.182AS39351 31173 Services ABSE 54872026-06-19
103.81.231.93AS203020 HostRoyale TechnologiesUS 52892026-06-20
146.70.201.108AS9009 M247 Europe SRLJP 841402026-06-21
154.47.29.11AS212238 Datacamp LimitedHR 46752026-06-23

Related CVE-2023-44487 IPs (CANCEL RST — separate campaign)

152.42.217.112 129.226.83.92 43.128.73.4

Behavioral signatures

IndicatorValue
RST_STREAM error code0x5 (STREAM_CLOSED) — all RSTs
Concurrent sessions per wave8–9
Session duration~15 seconds per wave
UA profiles observed5 distinct (Chrome 120/124/131 macOS, Edge 101 Windows, Safari 18 macOS) — no single fixed platform anchor
Target port443 (TLS only)
ProtocolHTTP/2 (h2) — no h2c observed
ASNs of interestAS39351, AS203020, AS9009, AS212238

09 Detection signatures

Suricata — CVE-2026-23918 STREAM_CLOSED Rapid Reset

alert tcp any any -> $HTTP_SERVERS 443 (
  msg:"CVE-2026-23918 Apache mod_http2 STREAM_CLOSED Rapid Reset Scan";
  flow:established,to_server;
  content:"|50 52 49 20 2a 20 48 54 54 50 2f 32 2e 30 0d 0a 0d 0a 53 4d 0d 0a 0d 0a|";
  comment:"HTTP/2 client magic (PRI * HTTP/2.0)";
  threshold:type both, track by_src, count 5, seconds 10;
  detection_filter:track by_src, count 3, seconds 5;
  metadata:cve CVE-2026-23918, confidence high;
  classtype:attempted-dos; sid:9002691801; rev:1;
)

# Tighter: STREAM_CLOSED RST (binary RST_STREAM frame with error 0x00000005)
alert tcp any any -> $HTTP_SERVERS 443 (
  msg:"CVE-2026-23918 RST_STREAM STREAM_CLOSED error in HTTP/2";
  flow:established,to_server;
  content:"|00 00 04 03 00|";   comment:"RST_STREAM frame header (len=4, type=0x3, flags=0x0)";
  content:"|00 00 00 05|"; within:4;  comment:"error code STREAM_CLOSED = 0x5";
  threshold:type both, track by_src, count 8, seconds 30;
  metadata:cve CVE-2026-23918, confidence high;
  classtype:attempted-dos; sid:9002691802; rev:1;
)

Apache httpd — rate-limit RST_STREAM(STREAM_CLOSED)

# In httpd.conf or mod_http2 config:
H2MaxSessionStreams 20
H2MaxWorkerIdleSeconds 30
H2StreamMaxMemSize 65536
# Monitor: grep "h2_rst_error:STREAM_CLOSED" in cowrie events
# or Apache error.log for "RST_STREAM" with status 0x5

Nginx / HAProxy upstream — mitigation

# Nginx: limit concurrent HTTP/2 streams
http2_max_concurrent_streams 20;
limit_req_zone $binary_remote_addr zone=h2_limit:10m rate=30r/m;

# HAProxy: bind with h2 rate limits
bind :443 ssl crt /etc/ssl/cert.pem alpn h2,http/1.1 \
     maxconn 100

10 Collection methodology

Data collected by the cowrAI distributed SSH/Telnet honeypot fleet, deployed across multiple cloud providers and geographic regions. HTTP/2 traffic was captured by apachelure, a custom lure daemon presenting a realistic Apache HTTPS endpoint on port 443, deployed fleet-wide as an anchor-tier lure.

apachelure logs each captured HTTP header individually, plus structured events for HTTP/2 frame-level telemetry (connection preface, frame-level detail, RST_STREAM events, and session end). All events are ingested in near-real-time into the fleet's operational data store and cross-referenced against a separate analytics pipeline for fleet-wide aggregation.

Correction (post-publication fact-check): an earlier version of this report stated that HTTP/2 pseudo-headers (:method, :path, :authority) were not captured during this campaign. That was incorrect — apachelure's HEADERS frame logging already includes the full pseudo-header set, and that data (see §07 "Requested paths") is what identified the scanners' actual targets (.env/.git/docker-compose secret-exposure paths).