Description
get_validators_for_transaction in backend/consensus/vrf.py uses a mutable default argument for the random number generator. The rng object is created once at module import time and shared across every call, making the validator selection sequence predictable.
Root Cause
def get_validators_for_transaction(
nodes: list[dict],
num_validators: int | None = None,
rng=np.random.default_rng(seed=int(datetime.now().timestamp())), # ← evaluated ONCE at import
) -> list[dict]:
Python evaluates default arguments at function definition time (i.e., module load time), not at call time. This means:
- All calls share the same stateful RNG instance
- The seed is
int(datetime.now().timestamp()) knowable by anyone who knows when the process started
- An attacker with knowledge of the server start time can predict the entire future sequence of validator selections
This fundamentally undermines the purpose of a VRF (Verifiable Random Function) in a consensus system.
Expected Behavior
Each call should use an independently seeded RNG, or the caller should inject a cryptographically secure RNG.
Fix
def get_validators_for_transaction(
nodes: list[dict],
num_validators: int | None = None,
rng=None,
) -> list[dict]:
if rng is None:
rng = np.random.default_rng()
...
Severity
Critical undermines consensus security; validator selection becomes predictable.
Description
get_validators_for_transactioninbackend/consensus/vrf.pyuses a mutable default argument for the random number generator. Therngobject is created once at module import time and shared across every call, making the validator selection sequence predictable.Root Cause
Python evaluates default arguments at function definition time (i.e., module load time), not at call time. This means:
int(datetime.now().timestamp())knowable by anyone who knows when the process startedThis fundamentally undermines the purpose of a VRF (Verifiable Random Function) in a consensus system.
Expected Behavior
Each call should use an independently seeded RNG, or the caller should inject a cryptographically secure RNG.
Fix
Severity
Critical undermines consensus security; validator selection becomes predictable.