vielite's blog

QA-12: Order Assumption in get_account_base_nonces Can Misassign Nonces

March 22, 2026
2 min read
Table of Contents
monad-qa-12-order-assumption-nonces

Summary

The nonce-fetching logic deduplicates addresses through a HashSet, then zips backend results back to addresses by position even though the trait contract does not guarantee output ordering.

Vulnerability details

2025-09-monad/bft/monad-eth-block-policy/src/lib.rs
let addresses = addresses.unique().collect::<HashSet<&'a Address>>();
// ...
let cache_miss_statuses = self.get_account_statuses(
state_backend,
&Some(extending_blocks),
cache_misses.iter().map(|(address, _)| *address),
&base_seq_num,
)?;
account_nonces.extend(cache_misses.into_iter().zip_eq(cache_miss_statuses).map(
|((address, possible_nonces), status)| {
let nonce = status.map_or(0, |status| status.nonce);
(address, possible_nonces.map_or(nonce, |possible_nonces| {
NonceUsage::apply_possible_nonces_to_account_nonce(nonce, possible_nonces)
}))
},
));

Impact

A backend that returns results in a different order could silently assign wrong nonces to wrong addresses and create inconsistent block validation outcomes.

Recommendation

Bind returned values to addresses explicitly or document and enforce ordering at the trait level.