Lucene search

K
code423n4Code4renaCODE423N4:2022-10-PALADIN-FINDINGS-ISSUES-247
HistoryOct 30, 2022 - 12:00 a.m.

Owner can bypass ERC20 recovery restrictions and take all rewards

2022-10-3000:00:00
Code4rena
github.com
6
erc20 recovery bypass
owner privileges
reward tokens
vulnerability impact
token sweep
mitigation steps.

Lines of code
<https://github.com/code-423n4/2022-10-paladin/blob/d6d0c0e57ad80f15e9691086c9c7270d4ccfe0e6/contracts/WardenPledge.sol#L653-L661&gt;

Vulnerability details

Impact

There is a function that is intended to be used to recover ERC20 tokens that were sent to the WardenPledge contract by accident. The function is only usable by the owner and contains a check that no tokens can be taken which are currently whitelisted as reward tokens. However, the owner also has enough privileges to bypass that check and can instantly take all reward tokens that are part of currently running pledges.

Proof of Concept

The function to move out accidentally sent ERC20 tokens as described under #Impact is recoverERC20:

/**
* @notice Recovers ERC2O tokens sent by mistake to the contract
* @dev Recovers ERC2O tokens sent by mistake to the contract
* @param token Address tof the EC2O token
* @return bool: success
*/
function recoverERC20(address token) external onlyOwner returns(bool) {
    if(minAmountRewardToken[token] != 0) revert Errors.CannotRecoverToken();

    uint256 amount = IERC20(token).balanceOf(address(this));
    if(amount == 0) revert Errors.NullValue();
    IERC20(token).safeTransfer(owner(), amount);

    return true;
}

It can be seen that it reverts if minAmountRewardToken[token] != 0, which means the token can be used during the creation of a new pledge and also that there might be currently pledges running with that token as a reward.

However, the owner can use the removeRewardToken function at will to β€œde-whitelist” any such tokens, which would allow him to sweep all reward tokens with recoverERC20 right after:

function removeRewardToken(address token) external onlyOwner {
    if(token == address(0)) revert Errors.ZeroAddress();
    if(minAmountRewardToken[token] == 0) revert Errors.NotAllowedToken();
    
    minAmountRewardToken[token] = 0;
    
    emit RemoveRewardToken(token);
}

Tools Used

Manual Review

Recommended Mitigation Steps

  • Option 1: make the sweep of tokens a 2-step process where the second step is timelocked and the first step emits an event to notify users that a sweep is about to happen for a certain token. This gives users the time and opportunity to react accordingly.
  • Option 2: track all currently running pledges for a certain token and only enable recovery for that token if there are no corresponding pledges running.

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

All reactions