For the complete documentation index, see llms.txt. This page is also available as Markdown.

75371 bc high unlimited p2p connections lead to node isolation and rpc crash

Submitted on Apr 28th 2026 at 18:43:46 UTC by @DeltaXV for Audit Comp | Base Azul

  • Report ID: #75371

  • Report Type: Blockchain/DLT

  • Report severity: High

  • Target: https://github.com/base/base/tree/v0.8.0-rc.28

  • Impacts:

    • RPC API crash affecting programs with greater than or equal to 25% of the market capitalization on top of the respective layer

    • Unintended chain split (network partition)

    • Increasing network processing node resource consumption by at least 30% without brute force actions, compared to the preceding 24 hours

Description

Brief/Intro

base-consensus accepts an unlimited number of inbound libp2p connections because connection_limits::Behaviour is never added to the Swarm and the CLI parameters peers_hi / peers_lo are emitted as metrics only — never wired to the swarm. An attacker can establish thousands of permanent authenticated connections from a single IP, exhausting the process file descriptor limit (EMFILE) on production systems, isolating the node from the gossip network, and crashing its RPC.

Vulnerability Details

The libp2p Behaviour struct in base/crates/consensus/gossip/src/behaviour.rs has four members:

libp2p::connection_limits::Behaviour is absent. Without it, libp2p 0.56 enforces zero connection limits — the Swarm accepts every inbound TCP connection until OS resources are exhausted.

The CLI flags --p2p.peers.hi (default 30) and --p2p.peers.lo (default 20) are parsed by base/crates/client/cli/src/p2p.rs but only written to Prometheus metrics in base/bin/consensus/src/metrics.rs. They never appear in NetworkConfig, NetworkBuilder, or GossipDriverBuilder. The configured limit of 30 peers has zero effect.

Additionally, the production binary never raises the file descriptor soft limit:

On a standard Linux system, ulimit -n defaults to 1024. With ~27 FDs used at baseline, ~997 attacker connections exhaust the pool.

Each attacker connection completes the full Noise XX handshake + Yamux muxer negotiation, making it a permanent established connection. The idle_connection_timeout=60s is bypassed because Yamux keeps open substreams that prevent the idle detection from firing (confirmed libp2p issue #5190, still open in libp2p 0.56).

Impact Details

Production nodes running with the default OS file descriptor limit (ulimit -n 1024) have their FD pool exhausted by ~997 attacker connections, causing the gossip mesh to collapse and the RPC to freeze — any dApp or service relying on that node loses access to current chain state. Even on nodes with raised FD limits, the attack causes +30% memory and +318% CPU increase from a single IP with zero ongoing cost.

References

Add any relevant links to documentation or code

https://gist.github.com/DeltaXV/770c383ac94b80812142e69e444fa2b9

Proof of Concept

1

create the attack.py file and paste the following script:

2

Start the devnet:

3

Wait for all containers to be healthy:

4

Take baseline measurement:

5

Run the attack (in a separate terminal):

6

Observe the impact:

All connections from a single IP. Zero failures. Zero authentication beyond a fresh random keypair. Connections are permanent — they survive indefinitely with zero attacker maintenance after the initial 50-second setup.

Remediation

Rate limits in p2p node mechanism is crucial to avoid this type of attack where further exploitation can lead to more damage.

Was this helpful?