Skip to content

Security: GossipSub Memory Exhaustion via Unbounded Remote Topic Subscriptions #349

@johannamoran

Description

@johannamoran

Summary

A potential memory exhaustion vulnerability has been identified in cpp-libp2p's GossipSub implementation. A remote peer may be able to cause unbounded growth of gossip routing state by sending a large number of unique topic subscription entries.
The issue arises because incoming subscription lists are processed without truncation and there is currently no limit on the number of distinct topics a single peer may subscribe to. As a result, attacker-controlled topic identifiers can accumulate indefinitely in per-peer and global subscription tracking structures.

This issue was responsibly reported by @tonghuaroot and verified by @seetadev through private disclosure. We thank them for their careful analysis, responsible reporting process, and ecosystem-wide review of related GossipSub implementations.

Affected Component

  • GossipSub
  • Remote subscription tracking
  • Message subscription processing

Affected areas include:

  • src/protocol/gossip/impl/message_parser.cpp
  • src/protocol/gossip/impl/gossip_core.cpp
  • src/protocol/gossip/impl/remote_subscriptions.cpp
  • src/protocol/gossip/impl/peer_context.hpp

Impact

A connected peer can continuously submit SUBSCRIBE messages containing previously unseen topic identifiers.

Because these topic identifiers are stored without an effective upper bound:

  • Per-peer subscription state grows indefinitely.
  • Global topic subscription structures grow indefinitely.
  • Memory consumption increases linearly with attacker input.
  • Nodes may eventually experience memory pressure, degraded performance, or process termination.

This issue affects availability and may enable a denial-of-service attack against exposed GossipSub nodes.

Attack Requirements

Unbounded Subscription Processing
Incoming protobuf subscription entries are forwarded directly to subscription handling logic without limiting the number of entries processed from a single RPC message.

Current logic iterates over every subscription entry and forwards it to the receiver:

for (const auto &s : pb_msg_->subscriptions()) {

receiver.onSubscription(from, s.subscribe(), s.topicid());

}

Unbounded Per-Peer Topic Tracking

Subscription handling inserts topics into:
peer->subscribed_to

which is implemented as:
std::set

with no maximum size.
When a previously unseen topic is received:
auto res = getItem(topic, true);

creates a corresponding TopicSubscriptions entry.

As a result, a malicious peer can continuously introduce new topic identifiers, causing both:

  • Growth of the peer's subscription set.
  • Growth of the global topic subscription map.

Reproduction Concept

A peer repeatedly sends GossipSub SUBSCRIBE messages containing unique topic identifiers:

topic-1
topic-2
topic-3

topic-N

Each new topic causes additional memory allocation and state retention.

The growth is proportional to the number of unique topics accepted by the victim node.

Related Ecosystem Findings

This issue is closely related to previously identified GossipSub subscription-flooding vulnerabilities in other libp2p implementations.

In particular, js-libp2p introduced protections including:

  • Per-RPC subscription limits.
  • Per-peer topic subscription limits.

The same defense-in-depth approach is applicable here.

Recommended Remediation

  1. Add Per-RPC Subscription Limits

Introduce a maximum number of subscription entries processed from a single incoming RPC message.

Example:

static constexpr size_t kMaxSubscriptionsPerRpc = ...;

Additional entries should be ignored or rejected.

2. Add Per-Peer Topic Limits

Introduce a maximum number of accumulated topic subscriptions per peer.
Example:
static constexpr size_t kMaxSubscribedTopicsPerPeer = 16384;

Before inserting a new topic:
if (peer->subscribed_to.size() >= kMaxSubscribedTopicsPerPeer &&
peer->subscribed_to.count(topic) == 0) {
return;
}

This prevents memory growth across multiple RPC messages.

3. Add Regression Tests

Tests should verify:

  • Large subscription floods are truncated.
  • Per-peer topic limits are enforced.
  • Memory growth remains bounded.
  • Existing unsubscribe behavior continues to function correctly.

Severity Assessment

Availability impact is potentially high because attacker-controlled input can trigger unbounded memory growth.

Provisional severity assessment:

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

CVSS Score: 7.5 (High)

Acknowledgements

Special thanks to @tonghuaroot for responsibly reporting this issue, providing detailed source-level analysis, identifying parallels across multiple libp2p implementations, and helping improve the resilience of the broader libp2p ecosystem. The issue was verified by @seetadev.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions