Lucene search

K
code423n4Code4renaCODE423N4:2023-10-ETHENA-FINDINGS-ISSUES-593
HistoryOct 30, 2023 - 12:00 a.m.

Vulnerability in rescueTokens and _beforeTokenTransfer Functions Allows Unrestricted Transfer to Contracts

2023-10-3000:00:00
Code4rena
github.com
24
erc20
vulnerability
solidity

AI Score

7.3

Confidence

High

Lines of code
<https://github.com/code-423n4/2023-10-ethena/blob/main/contracts/StakedUSDe.sol#L245-L252&gt;

Vulnerability details

Impact

The rescueTokens function in the provided Solidity contract allows the contract owner to transfer ERC20 tokens to any address, and the _beforeTokenTransfer hook allows transfers involving addresses with the FULL_RESTRICTED_STAKER_ROLE. However, both functions lack checks to ensure that the destination address is not a contract. This oversight can lead to potential issues, such as funds becoming stuck in contracts that are not designed to handle arbitrary token transfers. Malicious actors could exploit these vulnerabilities to intentionally lock up tokens in contracts, disrupting the contract’s functionality.

Proof of Concept

File: contracts/StakedUSDe.sol

138: function rescueTokens(
        address token,
        uint256 amount,
        address to
    ) external onlyRole(DEFAULT_ADMIN_ROLE) {
        if (address(token) == asset()) revert InvalidToken();
        IERC20(token).safeTransfer(to, amount);
    }

245: function _beforeTokenTransfer(
        address from,
        address to,
        uint256
    ) internal virtual override {
        if (hasRole(FULL_RESTRICTED_STAKER_ROLE, from) && to != address(0)) {
            revert OperationNotAllowed();
        }
        if (hasRole(FULL_RESTRICTED_STAKER_ROLE, to)) {
            revert OperationNotAllowed();
        }
    }

Attack Scenarios

For rescueTokens Function:

  • An attacker deploys a malicious contract that does not implement a proper ERC20 token receiver function.
  • The contract owner uses the rescueTokens function to transfer tokens to the malicious contract address.

For _beforeTokenTransfer Hook:
An attacker with FULL_RESTRICTED_STAKER_ROLE transfers tokens to a malicious contract address that can accept tokens but should not.

Tools Used

VS Code, Manual Review

Recommended Mitigation Steps

To mitigate these vulnerabilities, implement checks in both the rescueTokens function and the _beforeTokenTransfer hook to ensure that the destination address is not a contract.

For rescueTokens Function:

function rescueTokens(
    address token,
    uint256 amount,
    address to
) external onlyRole(DEFAULT_ADMIN_ROLE) {
    if (address(token) == asset()) revert InvalidToken();
    require(!Address.isContract(to), "Recipient is a contract");
    IERC20(token).safeTransfer(to, amount);
}



function _beforeTokenTransfer(
    address from,
    address to,
    uint256
) internal virtual override {
    if (hasRole(FULL_RESTRICTED_STAKER_ROLE, from) && to != address(0) && Address.isContract(to)) {
        revert OperationNotAllowed();
    }
    if (hasRole(FULL_RESTRICTED_STAKER_ROLE, to)) {
        revert OperationNotAllowed();
    }
}

In these modified versions:

  • The Address.isContract() function from the OpenZeppelin library is used to check if the recipient address (to) is a contract.
  • If the recipient is a contract, the functions will revert, preventing the transfer and ensuring that tokens are only transferred to externally owned accounts.

Assessed type

Token-Transfer


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

All reactions

AI Score

7.3

Confidence

High