The vulnerability, identified as GHSA-6973-8887-87ff, stems from an integer truncation and lack of bounds checking in the nimiq-block crate. The core issue resides in how several proof verification functions handled signer information stored in a BitSet. An attacker could craft a proof with signer indices outside the valid range (e.g., slot and slot + 65536).
The vulnerable functions, SkipBlockProof::verify, TendermintProof::verify, and DoubleVoteProof::verify, would first perform a quorum check by reading the .len() of the BitSet. This length could be artificially inflated by the out-of-range indices. Subsequently, when aggregating the public keys of the signers, these functions would cast the usize index to a u16. This truncation caused the out-of-range indices to collide with valid in-range indices (e.g., slot + 65536 becomes slot after as u16). This flaw allowed a malicious validator to bypass the 2f+1 quorum check with significantly fewer real signatures than required, as a single signature could be counted multiple times.
The patch addresses this by introducing a new function, checked_signer_slots, which explicitly validates that all signer indices in the BitSet are within the allowed range (< Policy::SLOTS and <= u16::MAX) before they are used. The vulnerable verify methods in SkipBlockProof, TendermintProof, and DoubleVoteProof were all updated to use this new validation function. This ensures that the quorum check is performed on a sanitized list of signers and that integer truncation can no longer lead to a bypass. Any proof containing out-of-range signer indices is now correctly rejected.