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.
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,);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.