vielite's blog

QA-01: No Deduplication of Peers in ConfirmGroup Allows Traffic Amplification

April 2, 2026
0 min read
Table of Contents
monad-qa-01-no-deduplication-of-peers

Summary

ConfirmGroup.peers is accepted as long as it contains the receiver and does not exceed max_group_size, but the peer list is not deduplicated before group construction.

Details

The secondary client forwards the peer vector into group construction, where the implementation removes only self and sorts the remaining peers. It does not enforce uniqueness. A malicious validator can therefore repeat the same NodeId multiple times and force redundant sends to the same destination.

2025-09-monad/bft/monad-raptorcast/src/raptorcast_secondary/client.rs
if confirm_msg.peers.len() > confirm_msg.prepare.max_group_size {
return;
}
if !confirm_msg.peers.contains(&self.client_node_id) {
return;
}
let group = GroupAsClient::new_fullnode_group(
confirm_msg.peers,
&self.client_node_id,
confirm_msg.prepare.validator_id,
round_span,
);
2025-09-monad/bft/monad-raptorcast/src/util.rs
pub fn new_fullnode_group(
all_peers: Vec<NodeId<CertificateSignaturePubKey<ST>>>,
self_id: &NodeId<CertificateSignaturePubKey<ST>>,
validator_id: NodeId<CertificateSignaturePubKey<ST>>,
round_span: RoundSpan,
) -> Self {
let mut sorted_other_peers = all_peers;
if self_id != &validator_id {
let self_index = sorted_other_peers
.iter()
.position(|peer| peer == self_id)
.expect("Could not find own node id");
sorted_other_peers.swap_remove(self_index);
}
sorted_other_peers.sort();

Impact

The result is avoidable traffic amplification and extra processing work. The blast radius is capped by max_group_size, but uniqueness should still be enforced on the path.

Recommendation

Deduplicate ConfirmGroup.peers before creating the group object.