CVE-2026-40094
Description
nimiq-blockchain provides persistent block storage for Nimiq's Rust implementation. In versions 1.3.0 and prior, network-libp2p discovery accepts signed PeerContact updates from untrusted peers and stores them in a peer contact book, eventually leading to address book crash. A PeerContact can legally contain an empty addresses list (no intrinsic validation enforces non-empty). Later, PeerContactBook::known_peers builds an address book by taking addresses.first().expect("every peer should have at least one address"). If the attacker has inserted a signed peer contact with addresses=[], any call to get_address_book (RPC/web client) can panic and crash the node/RPC task depending on panic settings. This issue has been fixed in version 1.4.0.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Untrusted peers can crash Nimiq nodes by sending a signed PeerContact with an empty address list, causing a panic in known_peers().
Vulnerability
In nimiq-blockchain versions 1.3.0 and prior, the network-libp2p discovery component accepts signed PeerContact updates from untrusted peers and stores them in the peer contact book. A PeerContact can legally contain an empty addresses list because no intrinsic validation enforces non-empty addresses. Later, PeerContactBook::known_peers builds an address book by calling addresses.first().expect("every peer should have at least one address"). If an attacker inserts a signed peer contact with addresses=[], any call to get_address_book (RPC/web client) will panic and crash the node or RPC task, depending on panic settings [3].
Exploitation
An attacker with network access can send a signed PeerContact update containing an empty addresses list. No authentication or special privileges are required. The node accepts the update and stores it in the peer contact book. Subsequently, any invocation of get_address_book (e.g., via RPC or web client) triggers known_peers, which panics on the empty list. The attacker can repeat this to cause repeated crashes, leading to denial of service [2][3].
Impact
Successful exploitation results in a denial of service (DoS). The node process or the RPC task crashes, making the node unavailable. There is no information disclosure, data corruption, or remote code execution. The impact is limited to service disruption [3].
Mitigation
The vulnerability is fixed in version 1.4.0, released on 2026-05-20 [1]. The fix skips peers with empty addresses in known_peers() instead of panicking [2]. No workarounds are available; upgrading to v1.4.0 is the only mitigation. The issue is not listed on CISA's Known Exploited Vulnerabilities (KEV) catalog.
AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
3(expand)+ 1 more
- (no CPE)
- (no CPE)range: <=1.3.0
- Range: <=1.3.0
Patches
157836cb0cefaFix empty-address panic in known_peers()
1 file changed · +5 −13
network-libp2p/src/discovery/peer_contacts.rs+5 −13 modified@@ -512,20 +512,12 @@ impl PeerContactBook { pub fn known_peers(&self) -> Vec<(PeerId, PeerInfo)> { self.peer_contacts .iter() - .map(|(peer_id, contact)| { - ( + .filter_map(|(peer_id, contact)| { + let address = contact.contact.inner.addresses.first()?.clone(); + Some(( *peer_id, - PeerInfo::new( - contact - .contact - .inner - .addresses - .first() - .expect("every peer should have at least one address") - .clone(), - contact.contact.inner.services, - ), - ) + PeerInfo::new(address, contact.contact.inner.services), + )) }) .collect() }
Vulnerability mechanics
Root cause
"Missing validation for empty addresses list in PeerContact processing allows a panic when known_peers() calls .expect() on an empty list."
Attack vector
An unauthenticated remote attacker sends a signed PeerContact message containing an empty addresses list (addresses=[]). The network-libp2p discovery layer accepts this contact because no intrinsic validation enforces a non-empty address list. The poisoned contact is stored in the PeerContactBook. When any component calls known_peers() — for example via the get_address_book RPC or a web client — the function attempts to call .expect("every peer should have at least one address") on an empty iterator, causing a panic that crashes the node or the RPC task depending on panic configuration [CWE-754].
Affected code
The vulnerability is in network-libp2p/src/discovery/peer_contacts.rs within the PeerContactBook::known_peers() method. The function iterates over peer_contacts and unconditionally calls .expect("every peer should have at least one address") on the result of addresses.first(), assuming the list is always non-empty. No upstream validation in the discovery layer rejects PeerContact messages with an empty addresses list.
What the fix does
The patch replaces the .map() + .expect() chain with .filter_map() in known_peers() [patch_id=878907]. Instead of panicking when addresses is empty, the new code calls addresses.first() which returns None for an empty vector, and filter_map silently skips that peer entry. This closes the DoS vector by tolerating malformed peer contacts rather than crashing.
Preconditions
- networkAttacker must be able to send a signed PeerContact message to the victim node over the network.
- configThe victim node must be running a vulnerable version (≤ 1.3.0) of the nimiq-blockchain software with network-libp2p discovery enabled.
- authNo authentication is required — the attack is unauthenticated (PR:N).
- inputThe attacker's PeerContact must contain an empty addresses list (addresses=[]).
Generated on May 20, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
3News mentions
0No linked articles in our index yet.