Lucene search

K
code423n4Code4renaCODE423N4:2023-08-VERWA-FINDINGS-ISSUES-443
HistoryAug 10, 2023 - 12:00 a.m.

Double voting in GaugeController

2023-08-1000:00:00
Code4rena
github.com
3
double voting
gaugecontroller
votingescrow
manipulative influence
delegation
undelegation
vulnerability
mitigation measures.

Lines of code
<https://github.com/code-423n4/2023-08-verwa/blob/a693b4db05b9e202816346a6f9cada94f28a2698/src/VotingEscrow.sol#L397-L403&gt;

Vulnerability details

Impact

Voting with the same collateral multiple times by delegating and undelegating, a process that could manipulatively influence(increase) the weight of a particular lending market where the malicious actor is the major Liquidity provider.

Proof of Concept

The protocol allows depositors to delete to another address, but this feature comes with a problem:

  1. It allows double voting with the same collateral, as no prevention for this as confirmed by the sponsor that no mitigation for yet <https://drive.google.com/file/d/1_542keetegWF3idpF3bAqnNjxL9r9eUy/view?usp=sharing&gt;

  2. In function createLock(uint256 _value) external payable nonReentrant { user creates a lock by depositing value, in return an amount of voting power in given, which enables the depositor to participate in voting for preferred lending market. According to the documentation.

Users can lock up CANTO (for five years) in the VotingEscrow contract to get veCANTO. They can then vote within GaugeController for different lending markets that are white-listed by governance.

Also, the protocols allows delegation of voting power to another address function delegate(address _addr) external nonReentrant {

 if (delegatee == msg.sender) {
            // Delegate
            fromLocked = locked_;
            toLocked = locked[_addr];

In VotingEscrow. _delegate, the new delegatee amount is updated to that of the delegator:

 if (action == LockAction.DELEGATE) {
            newLocked.delegated += value;
            emit Deposit(addr, uint256(int256(value)), newLocked.end, action, block.timestamp);

The implication of this is that, this new address now has the power to vote in GaugeController.vote_for_gauge_weights(), the problem with this is that, the real owner can later reclaim power by undelegating according to <https://github.com/code-423n4/2023-08-verwa/blob/a693b4db05b9e202816346a6f9cada94f28a2698/src/VotingEscrow.sol#L385C9-L385C72&gt;
_delegate(delegatee, fromLocked, value, LockAction.UNDELEGATE); where value is now retrieved from delegatee and retained by the previous owner who now has same power to vote again for the same lending market. This means a malicious actor can switch address to vote for a lending market of choice(where he has major shares to get more REWARD).

The reason for this attack is that when delegating, only value changes

   if (action == LockAction.DELEGATE) {
            newLocked.delegated += value;
            emit Deposit(addr, uint256(int256(value)), newLocked.end, action, block.timestamp);
        } else {
            newLocked.delegated -= value;
            emit Withdraw(addr, uint256(int256(value)), action, block.timestamp);

Potential Attack Scenario:

1. Attacker A locks tokens and delegates voting power to address B.
2. Attacker A can now vote using address B's voting power.
3. Attacker A undelegates, but retains the voting power.
4. Now, Attacker A can vote again using their original address and the delegated address B, effectively 
double voting.

Tools Used

Manual review

Recommended Mitigation Steps

Implement checks within the delegation process to ensure that the same voting power cannot be delegated to two different addresses. This could involve maintaining a record of previously delegated votes for each user and preventing new delegations until undelegation or a specific cooldown period has passed.

Assessed type

Context


The text was updated successfully, but these errors were encountered:

All reactions