← Back to Research
Research · August 10, 2026

rusty-kaspa gRPC pre-auth HTTP/2 stream flood causing inbound-peering exhaustion and eviction

Simon Morley·3 min read

A pre-auth HTTP/2 stream flood on the rusty-kaspa tonic gRPC P2P endpoint exhausts inbound peering capacity by evicting honest peers and denying new admissions.

Why this matters

This attack degrades inbound-peering availability for rusty-kaspa nodes. A single unauthenticated host can evict all honest inbound peers and block new connections using minimal resources, bypassing the intended --maxinpeers limit due to lazy enforcement.

How the attack works

The attack targets the rusty-kaspa tonic gRPC P2P service (/protowire.P2P/MessageStream). The connection_handler.rs:222 NewPeer admission path lacks an admission-time gate: it applies no TLS, IP-allowlist, ban check, per-IP cap, or concurrency layer. The only inbound bound (--maxinpeers) is enforced lazily and randomly by the connection manager (connectionmanager/lib.rs:247) on a ~30-second tick. An attacker opens ~512 pre-auth HTTP/2 streams. This causes two effects: (1) at the 30-second tick, random eviction removes 100% of honest inbound peers; (2) the serial Hub event loop (hub.rs:45) creates a head-of-line stall that denies 100% of honest inbound admission. These 100% figures were measured on a devnet node configured with --maxinpeers=8; behaviour at the production default (128) was not separately measured.

Affected systems

  • Chain: Kaspa
  • Implementation: rusty-kaspa (commit 3cef6adaf2c79cfa34704070a49fe10d712b5729)
  • Components: p2p: tonic gRPC P2P service (/protowire.P2P/MessageStream), connection_handler.rs: NewPeer admission, connectionmanager: inbound eviction loop
  • Version: 1.1.0 (measured)

Evidence

  • Publicly documented: None (original NullRabbit research, no CVE assigned).
  • Independently reproduced by NullRabbit: Yes, via the reproducer kaspa-h1-harness.py (primitive kaspa_grpc_h2_preauth_stream_flood).
  • Measured under controlled conditions: Finding KAS-H1, measured 2026-06-02. A single host opening ~512 pre-auth HTTP/2 streams against a devnet node (rusty-kaspa 1.1.0, --maxinpeers=8) resulted in:
    • 100% of honest inbound peers evicted at the random 30-second tick (t=14.3 s).
    • 100% of honest inbound admission denied via serial-Hub head-of-line stall over an 18 s window.
    • Node RSS increase from 47 MB to 172 MB (+125 MB).
    • Node CPU approximately 0%.
  • Inferred but not reproduced: Not established.

Operator actions

  • Add an admission-time gate before NewPeer (connection_handler.rs:222): enforce per-IP connection and stream caps, consult the ban list, and require TLS or a handshake-proof before admission.
  • Make --maxinpeers a real synchronous admission bound at accept time, rather than a lazy random-eviction tick (connectionmanager/lib.rs:247).
  • Reserve inbound slots for established or outbound-verified peers.
  • Parallelize the Hub accept path to prevent head-of-line stalls.

Canonical references

Related attacks

  • NRDAX-T0064 instances:
    • cosmos_grpc_stream_flood (Cosmos)
    • ic_xnet_concurrency_cap (Internet Computer)
    • iota_grpc_stream_cap_dos (IOTA)
    • http2_settings_ack_stream_cap_bypass (HTTP/2)

Subscription call to action

Track attacks affecting Kaspa and other decentralised infrastructures by subscribing to NullRabbit briefs.

Analysis plus reproducer. No weaponised proof-of-concept code.

kasparusty-kaspagrpchttp2connection_exhaustionp2pinfrastructure-security
Publication policy:Why we publish these findings →

Related Posts