function delegateBySig doesn't cover case when delegatee = address(0), malicious users can lock other user's NFT(funds).
The delegateBySig() function does not validate the delegatee address.
when call delegateBySig(delegatee=address(0)), the delegatee is still self, but user checkpoints.votes will be reduced.
it will cause the NFT(funds) of the user being delegate to be locked, can no set other delegatee or NFT transfer
Here also because src = Alice, and the Alice's Checkpoints.votes=0, _moveVotingPower() reverts with an underflow error due to subtracting amount from 0.
The same thing, i.e. locking of NFTs(funds), can happen to the user himself as well:
If user A votes to address 0 in the delegateBySig function, _delegates[A] will be address 0.
Later, if user A votes to another address or transfers NFT, the _moveVotingPower function will fail due to underflow, which makes user A lose votes forever and cannot transfer NFT(funds).
This vulnerability is also true for the delegate function
Lines of code
https://github.com/code-423n4/2024-07-reserve/blob/main/contracts/p1/StRSRVotes.sol#L162 https://github.com/code-423n4/2024-07-reserve/blob/main/contracts/p1/StRSRVotes.sol#L166
Vulnerability details
Impact
function delegateBySig doesn't cover case when delegatee = address(0), malicious users can lock other user's NFT(funds).
The delegateBySig() function does not validate the delegatee address.
when call delegateBySig(delegatee=address(0)), the delegatee is still self, but user checkpoints.votes will be reduced. it will cause the NFT(funds) of the user being delegate to be locked, can no set other delegatee or NFT transfer
https://github.com/code-423n4/2024-07-reserve/blob/main/contracts/p1/StRSRVotes.sol#L166C1-L183C6
POC:
step1 - Alice has 1 NFT, Bob has 1 NFT, and Bob's delegatee is Alice, then Alice's Checkpoints.votes=2
step2 - Alice transfers its own NFT to Carol, then Alice's Checkpoints.votes=1
step3 - Alice call delegateBySig(address(0)), after Alice's Checkpoints.votes=0
step4 - Now Bob cannot modify the delegatee, nor can he transfer NFTs(funds). In fact, they are locked
What will happen will be as follows:
If Bob wants to transfer NFT or set a new delegatee, it will call _moveVotingPower()
https://github.com/code-423n4/2024-07-reserve/blob/main/contracts/p1/StRSRVotes.sol#L230C1-L243C14
Here also because src = Alice, and the Alice's Checkpoints.votes=0, _moveVotingPower() reverts with an underflow error due to subtracting amount from 0.
The same thing, i.e. locking of NFTs(funds), can happen to the user himself as well:
If user A votes to address 0 in the delegateBySig function, _delegates[A] will be address 0.
https://github.com/code-423n4/2024-07-reserve/blob/main/contracts/p1/StRSRVotes.sol#L220C1-L228C6
Later, if user A votes to another address or transfers NFT, the _moveVotingPower function will fail due to underflow, which makes user A lose votes forever and cannot transfer NFT(funds).
This vulnerability is also true for the delegate function
https://github.com/code-423n4/2024-07-reserve/blob/main/contracts/p1/StRSRVotes.sol#L162C1-L164C6
Proof of Concept
forge test -C test/StRSRVotes.t.sol -vvvvv
Tools Used
Foundry
Recommended Mitigation Steps
Consider preventing vote delegations to address(0)
Assessed type
Governance