Every CVE Search/ Get API key

CVE-2026-49866

libp2p: CPU DoS via oversized IHAVE and IWANT control message arrays

7.5 HighFix available

libp2p is a JavaScript Implementation of libp2p networking stack. Prior to 16.0.0, @libp2p/gossipsub defaultDecodeRpcLimits set maxIhaveMessageIDs and maxIwantMessageIDs to Infinity, allowing oversized IHAVE and IWANT control message arrays in message/decodeRpc.ts and gossipsub.ts to synchronously iterate roughly 180,000 message IDs per 4 MB frame and block the Node.js event loop. This issue is fixed in version 16.0.0.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
None
User interaction
None

What an attacker can affect

Confidentiality
None
Integrity
None
Availability
High

Exploit likelihood

0.63%Up 0.2 points since Jul 9, 2026
90%50%10%1%

What each source reports

CVE List Score used 7.5

libp2p: CPU DoS via oversized IHAVE and IWANT control message arrays

libp2p is a JavaScript Implementation of libp2p networking stack. Prior to 16.0.0, @libp2p/gossipsub defaultDecodeRpcLimits set maxIhaveMessageIDs and maxIwantMessageIDs to Infinity, allowing oversized IHAVE and IWANT control message arrays in message/decodeRpc.ts and gossipsub.ts to synchronously iterate roughly 180,000 message IDs per 4 MB frame and block the Node.js event loop. This issue is fixed in version 16.0.0.

Record
CVE-2026-49866
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Weakness
CWE-770
Updated
2026-11-02
EUVDEUVD-2026-42409 7.5

libp2p is a JavaScript Implementation of libp2p networking stack. Prior to 16.0.0, @libp2p/gossipsub defaultDecodeRpcLimits set maxIhaveMessageIDs and maxIwantMessageIDs to Infinity, allowing oversized IHAVE and IWANT control message arrays in message/decodeRpc.ts and gossipsub.ts to synchronously iterate roughly 180,000 message IDs per 4 MB frame and block the Node.js event loop. This issue is fixed in version 16.0.0.

Record
EUVD-2026-42409
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Updated
2026-11-02
GitHub AdvisoriesGHSA-cwc9-cp4j-mcvv 7.5

libp2p: CPU DoS via oversized IHAVE and IWANT control message arrays

Summary

gossipsub processes IHAVE and IWANT control messages by iterating every received message ID synchronously before doing anything with the results. There is no cap on how many IDs a single frame may contain. The default LP frame limit is 4MB, which fits roughly 180,000 message IDs. Iterating that many IDs blocks the Node.js event loop for around 200ms per call.

The two variants have different severity. For IHAVE there is a per-peer per-heartbeat counter that limits each peer to one full iteration per heartbeat, so causing a total stall requires around 10 Sybil peers. For IWANT there is no equivalent counter at all, so a single peer continuously streaming 4MB frames can hold the event loop above 80% utilisation indefinitely.

Details

No decode-time cap on message ID count (message/decodeRpc.ts:11-19)

export const defaultDecodeRpcLimits: DecodeRPCLimits = {
  maxSubscriptions: Infinity,
  maxMessages: Infinity,
  maxIhaveMessageIDs: Infinity,
  maxIwantMessageIDs: Infinity,
  maxIdontwantMessageIDs: Infinity,
  maxControlMessages: Infinity,
  maxPeerInfos: Infinity
}

These are the defaults unless the operator explicitly overrides opts.decodeRpcLimits. A TODO at gossipsub.ts:857 already notes the gap: // TODO: Check max gossip message size, before decodeRpc().

IHAVE iterates all IDs before truncating (gossipsub.ts:1311-1327)

messageIDs.forEach((msgId) => {                                                                            
  const msgIdStr = this.msgIdToStrFn(msgId)                                                               
  if (!this.seenCache.has(msgIdStr)) {                                                                     
    iwant.set(msgIdStr, msgId)                                                                            
  }                                                                                                       
})                                                                                                        
// truncation to GossipsubMaxIHaveLength (5000) only happens after the loop finishes                      

The per-peer flood counters (iasked, peerhave) do cap things eventually: each peer is limited to 10 IHAVE RPCs and 5000 IDs counted per heartbeat. After the first oversized IHAVE from a peer, subsequent ones are rejected cheaply. The problem is that the cap is per peer, so 10 Sybil peers each sending one 180K-ID IHAVE per heartbeat gives 10 x 150ms = 1500ms of synchronous work against a 1000ms heartbeat interval.

IWANT has no rate limit at all (gossipsub.ts:1377-1394)

messageIDs?.forEach((msgId) => {                     
  const msgIdStr = this.msgIdToStrFn(msgId)          
  const entry = this.mcache.getWithIWantCount(msgIdStr, id)                                               
  // ...                                                                                                  
})                                                                                                        

Unlike IHAVE, handleIWant has no peerhave or iasked equivalent. A single peer can send IWANT RPCs continuously with no per-heartbeat limit. Sending IWANT for non-existent messages does not affect the attacker's score (onIwantRcv is metrics-only), so there is no automatic disconnect. At 1 Gbps a 4MB frame arrives every ~32ms and takes ~135ms to process, giving roughly 81% event-loop utilisation from a single connection.

Attack Paths

IHAVE (requires ~10 Sybil peers) The attacker connects 10 peers, each subscribing to a topic the victim is on.…

Record
GHSA-cwc9-cp4j-mcvv
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Weakness
CWE-20, CWE-400, CWE-770
Updated
2026-11-02
NVD 7.5

libp2p is a JavaScript Implementation of libp2p networking stack. Prior to 16.0.0, @libp2p/gossipsub defaultDecodeRpcLimits set maxIhaveMessageIDs and maxIwantMessageIDs to Infinity, allowing oversized IHAVE and IWANT control message arrays in message/decodeRpc.ts and gossipsub.ts to synchronously iterate roughly 180,000 message IDs per 4 MB frame and block the Node.js event loop. This issue is fixed in version 16.0.0.

Record
CVE-2026-49866
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Weakness
CWE-770
Updated
2026-11-02
OSV 7.5

libp2p: CPU DoS via oversized IHAVE and IWANT control message arrays

libp2p is a JavaScript Implementation of libp2p networking stack. Prior to 16.0.0, @libp2p/gossipsub defaultDecodeRpcLimits set maxIhaveMessageIDs and maxIwantMessageIDs to Infinity, allowing oversized IHAVE and IWANT control message arrays in message/decodeRpc.ts and gossipsub.ts to synchronously iterate roughly 180,000 message IDs per 4 MB frame and block the Node.js event loop. This issue is fixed in version 16.0.0.

Record
CVE-2026-49866
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Weakness
CWE-770
Updated
2026-11-02
OSVGHSA-cwc9-cp4j-mcvv 7.5

libp2p: CPU DoS via oversized IHAVE and IWANT control message arrays

Summary

gossipsub processes IHAVE and IWANT control messages by iterating every received message ID synchronously before doing anything with the results. There is no cap on how many IDs a single frame may contain. The default LP frame limit is 4MB, which fits roughly 180,000 message IDs. Iterating that many IDs blocks the Node.js event loop for around 200ms per call.

The two variants have different severity. For IHAVE there is a per-peer per-heartbeat counter that limits each peer to one full iteration per heartbeat, so causing a total stall requires around 10 Sybil peers. For IWANT there is no equivalent counter at all, so a single peer continuously streaming 4MB frames can hold the event loop above 80% utilisation indefinitely.

Details

No decode-time cap on message ID count (message/decodeRpc.ts:11-19)

export const defaultDecodeRpcLimits: DecodeRPCLimits = {
  maxSubscriptions: Infinity,
  maxMessages: Infinity,
  maxIhaveMessageIDs: Infinity,
  maxIwantMessageIDs: Infinity,
  maxIdontwantMessageIDs: Infinity,
  maxControlMessages: Infinity,
  maxPeerInfos: Infinity
}

These are the defaults unless the operator explicitly overrides opts.decodeRpcLimits. A TODO at gossipsub.ts:857 already notes the gap: // TODO: Check max gossip message size, before decodeRpc().

IHAVE iterates all IDs before truncating (gossipsub.ts:1311-1327)

messageIDs.forEach((msgId) => {                                                                            
  const msgIdStr = this.msgIdToStrFn(msgId)                                                               
  if (!this.seenCache.has(msgIdStr)) {                                                                     
    iwant.set(msgIdStr, msgId)                                                                            
  }                                                                                                       
})                                                                                                        
// truncation to GossipsubMaxIHaveLength (5000) only happens after the loop finishes                      

The per-peer flood counters (iasked, peerhave) do cap things eventually: each peer is limited to 10 IHAVE RPCs and 5000 IDs counted per heartbeat. After the first oversized IHAVE from a peer, subsequent ones are rejected cheaply. The problem is that the cap is per peer, so 10 Sybil peers each sending one 180K-ID IHAVE per heartbeat gives 10 x 150ms = 1500ms of synchronous work against a 1000ms heartbeat interval.

IWANT has no rate limit at all (gossipsub.ts:1377-1394)

messageIDs?.forEach((msgId) => {                     
  const msgIdStr = this.msgIdToStrFn(msgId)          
  const entry = this.mcache.getWithIWantCount(msgIdStr, id)                                               
  // ...                                                                                                  
})                                                                                                        

Unlike IHAVE, handleIWant has no peerhave or iasked equivalent. A single peer can send IWANT RPCs continuously with no per-heartbeat limit. Sending IWANT for non-existent messages does not affect the attacker's score (onIwantRcv is metrics-only), so there is no automatic disconnect. At 1 Gbps a 4MB frame arrives every ~32ms and takes ~135ms to process, giving roughly 81% event-loop utilisation from a single connection.

Attack Paths

IHAVE (requires ~10 Sybil peers) The attacker connects 10 peers, each subscribing to a topic the victim is on.…

Record
GHSA-cwc9-cp4j-mcvv
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Weakness
CWE-20, CWE-400, CWE-770
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
@libp2p/gossipsub
npm
before 16.0.0
16.0.0

History

History
RecordedChangedSources
aliases, publishedEUVD
first indexedCVE List, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-49866 is a high vulnerability (CVSS 7.5) in Libp2p Js-libp2p, published July 8, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.63%, the 50th percentile. Fixed in @libp2p/gossipsub 16.0.0.

References

This page doesn't list everything

Left out here: the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open