← index

Vulnerability Disclosure: Twin Memory Exhaustion DoS Vulnerabilities in Core Lightning

An archive of delvingbitcoin.org · view original topic →

· Chand · #1 ·

Summary

This post details two distinct Denial-of-Service (DoS) vulnerabilities discovered in Core Lightning (CLN). Both vulnerabilities allowed a remote peer to trigger unbounded memory growth, ultimately leading to Out-of-Memory (OOM) system crashes.

The first vulnerability affected the connectd daemon and was patched in release v26.04. The second, related vulnerability affected the gossipd daemon and has been patched in release v26.06rc2. Both vulnerabilities stem from work initiated during my Summer of Bitcoin 2025 internship. All node operators are strongly advised to ensure they are running the latest patched versions.

Background

Core Lightning utilizes a multi-daemon architecture designed to isolate faults. The Lightning Network relies on a “gossip” protocol to propagate network state, including channel announcements, channel updates, and node announcements.

In CLN’s architecture, the connect daemon (connectd) receives external messages from peers and passes them to the gossip daemon (gossipd), which is responsible for managing the global view of the network. Because the network is inherently noisy, both daemons must operate with high efficiency. Furthermore, since they process untrusted external inputs, they must be robust against malicious message floods.

Vulnerability 1: connectd Message Queue Exhaustion

Discovery

This initial vulnerability was discovered using a new fuzz target I developed during my SoB internship, fuzz-gossipd-connectd, which was aimed at testing the robustness of gossipd’s state machines.

Here is a brief overview of how the fuzz target works (see the corresponding Pull Request for full details):

/* 0 - In each fuzz run, perform the following steps: */
void run(const u8* data, size_t size) {

  /* 1 - Mock the required setup for connectd-gossipd communication. */
  initialize_setup(data, size);

  /* 2 - State loop. Repeat until there's no more fuzzer data left. */
  while (size) {

  /* 3 - Use a fuzzer byte as decision variable to perform one of the three possible operations: */
  switch (consume_int(data) % OP_COUNT) {

    case NEW PEER:
      /* 3.1 - Register a fake peer to attribute messages to. */
      connectd_new_peer(daemon, create_random_peer_id());
  
    case RECV GOSSIP:
      /* 3.2.1 - Generate a cryptographically valid gossip. Can be one of: */
      /* - Channel Announcements */
      /* - Channel Updates */
      /* - Node Announcements */
      /* - Reply channel_range */
      /* - Reply short_channel_ids_end */
      msg = create_gossip_msg(data, size, random_peer());

      /* 3.2.2 - Parse the gossip created. */
      handle_recv_gossip(daemon, msg);

    case PEER GONE:
      /* 3.3 - Delete a peer from the network map. */
      connectd_peer_gone(daemon, remove_random_peer());
  }
}

The Bug

A remote attacker could trigger a DoS condition in the connectd sub-daemon by flooding it with a high volume of channel_update gossip messages. The root cause was a resource management issue in the inter-daemon message queue shared between connectd and gossipd.

do_enqueue() allocated a new copy of every incoming message. Under a high-volume message flood, messages were enqueued far faster than they could be dequeued and processed, causing the internal queue to grow without bounds. While a warning for excessive queue length (exceeding 250,000 items) existed, it was suppressed after the first instance due to a warned_once flag. This left no further indication of the ongoing memory consumption as the queue swelled into the millions of messages, ultimately consuming all available RAM and triggering swap death.

Vulnerability 2: gossipd Unknown SCID Map Exhaustion

Discovery

Ironically, this second vulnerability was discovered while I was verifying the fix for the connectd bug described above.

The Bug

Similar to the first bug, a remote attacker could trigger a DoS condition by flooding the node with a high volume of channel_update messages. However, in this case, the unbounded memory growth occurred in gossipd’s internal map for tracking unknown short channel IDs (SCIDs): unknown_scids.

When processing incoming updates via handle_recv_gossip(), gossipd assumes that if an SCID is unrecognized, it missed the original announcement and passes the data to query_unknown_channel(). To remember to query peers for these missing channels, the daemon calls add_unknown_scid(), which inserts every unique, fake SCID into an internal integer map (uintmap).

A continuous stream of unique, bogus SCIDs caused this uintmap to continuously allocate memory to split its internal nodes (split_node()). This caused gossipd’s memory consumption to balloon infinitely without logging any warnings.

Verification & Execution

Both vulnerabilities are triggerable using the exact same attack program. The program acts as a malicious Lightning Network peer that connects to a CLN node and orchestrates a message flood to trigger the crash:

  1. Initialization and Connection: The attacker establishes a connection to the victim CLN node.

  2. Initial Handshake: The attacker completes the standard init message handshake with the victim.

  3. The Malicious Flood: The attacker begins sending a continuous, high-volume stream of channel_update gossip messages to the victim node.

  4. Unbounded Growth and Crash: Depending on the unpatched vulnerability present, either connectd queues the messages until memory is exhausted, or gossipd processes the bogus SCIDs and continuously expands its uintmap until all physical RAM is depleted, resulting in a system freeze.

Criticality

Severity Medium/High (DoS)
Attack Vector Remote (Peer-to-Peer)
Consequence A remote attacker can reliably crash any publicly accessible CLN node by flooding it with peer-to-peer traffic. This requires no on-chain funds or channel relationship, making it a potent vector for disrupting network liquidity.

The Fixes

The architectural reasoning behind caching channel_update messages internally is to avoid losing gossip data for a channel that hasn’t been discovered yet. This allows the node to reach the latest state of a channel much faster when the corresponding channel_announcement eventually arrives, eliminating the need for the peer to rebroadcast the gossip. However, unbounded caching creates DoS vectors.

Patch 1: connectd Message Queue

The optimal fix for the connectd queue was to simply drop messages after a specific cutoff point, which was decided to be 500,000 messages. More details can be found in the Pull Request.

Patch 2: gossipd Unknown SCIDs

Fortunately, Rusty Russell (@rustyrussell) had already been working on a PR introducing an automatic compaction (garbage collection) mechanism for the gossip map. The patch introduces a new function that queries the store for the number of live and dead records, triggering a compaction if there are at least four times as many dead records as live ones (num_dead < 4 * num_live). This PR inadvertently fixed the second memory exhaustion issue. More details can be found in the Pull Request.

Disclosure Timelines

Vulnerability 1 (connectd exhaustion)

Vulnerability 2 (gossipd exhaustion)

Lessons Learned

These bugs emphasize that internal interfaces are attack surfaces too. Even if connectd handles external network throttling, it must also defend itself against internal floods. Fuzzing the IPC layer (daemon-to-daemon) is just as critical as fuzzing the external network layer.

Furthermore, this serves as a reminder of the interconnected nature of software vulnerabilities. The second bug would have been found sooner if someone had simply run the attack program I provided during my initial disclosure. I had already publicly posted the disclosure for the connectd DoS on my personal blog before independently finding the gossipd bug using the exact same script. It was entirely possible that a malicious actor could have read my first post, reproduced the attack program, and successfully exploited the network using the (then-unknown) second attack path. It is a fortunate coincidence that the compaction code was being revised at the same time.

Special thanks to my SoB 2025 mentor, Matt Morehouse, for guiding the entire process, especially the triage and disclosure.