Submitted by ast3ros, also found by Pechenite, dimulski, peanuts, KupiaSec, cccz, mojito_auditor, deth, 0xG0P1, zhaojie, osmanozdemir1, and rvierdiiev
This vulnerability allows for the minting and auctioning of an art piece that has not met the required quorum. It enables malicious voters to influence outcomes with fewer votes than what is stipulated by the protocol. This undermines a key invariant of the protocol:
https://github.com/code-423n4/2023-12-revolutionprotocol/blob/08ff070da420e95d7c7ddf9d068cbf54433101c4/README.md?plain=1#L291
The quorumVotes for an art piece are calculated at its creation as a fraction of the totalVotesSupply, which depends on the total supply of erc20VotingToken and erc721VotingToken:
https://github.com/code-423n4/2023-12-revolutionprotocol/blob/08ff070da420e95d7c7ddf9d068cbf54433101c4/packages/revolution/src/CultureIndex.sol#L209-L234
The totalVotesSupply is calculated using total supply of erc20VotingToken and erc721VotingToken at the time the piece is created. It intends to calculate all the voting power that can vote for this art piece.
https://github.com/code-423n4/2023-12-revolutionprotocol/blob/08ff070da420e95d7c7ddf9d068cbf54433101c4/packages/revolution/src/CultureIndex.sol#L284-L286
The vulnerability arises because the totalVotesSupply is computed based on the token supplies at the time of art piece creation. However, due to the block-based clock mode in the vote checkpoint, the total supplies of erc20VotingToken and erc721VotingToken can increase within the same block, resulting in an underestimation of totalVotesSupply and consequently, quorumVotes.
https://github.com/code-423n4/2023-12-revolutionprotocol/blob/08ff070da420e95d7c7ddf9d068cbf54433101c4/packages/revolution/src/base/VotesUpgradeable.sol#L85-L91
Possible attack scenarios include:
POC: This POC demonstrates the first case when a voter back-run the createPiece transaction to understate the totalVotesSupply and quorumVotes.
When the piece is created, only store the creationBlock. The quorum should not be stored. It should be calculated directly using VotesUpgradeable.getPastTotalSupply, this will return the value at the end of the corresponding block.
It ensures that quorumVotes accurately reflects the voting power at the end of the block in which the art piece was created, thereby mitigating the risk of quorum bypass through token supply manipulation within the same block.
rocketman-21 (Revolution) confirmed
