In Governance::state, the check for whether voting is still active uses block.timestamp < proposal.endTime, but in Governance::castVote users can vote when block.timestamp == proposal.endTime. This inconsistency creates a race condition where votes cast if the block is mined in the proposal.endTime may not be counted if the proposal state is checked in the same time.
castVote allows voting when block.timestamp == proposal.endTime
state considers voting ended when block.timestamp >= proposal.endTime
Both functions can be called in the same block
This race condition could allow manipulation of proposal outcomes by:
Preventing legitimate last-minute votes from being counted
Enabling premature proposal execution before all valid votes are tallied
Creating uncertainty about whether votes will be counted in the final block
Make the end time check consistent between state and castVote:
This ensures votes cast in the final block are always counted before the proposal state can change.
Additionally, consider adding a buffer period between voting end and execution to prevent race conditions.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.