Lines of code
<https://github.com/code-423n4/2023-10-ethena/blob/main/contracts/StakedUSDe.sol#L245-L252>
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.
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();
}
}
For rescueTokens Function:
For _beforeTokenTransfer Hook:
An attacker with FULL_RESTRICTED_STAKER_ROLE transfers tokens to a malicious contract address that can accept tokens but should not.
VS Code, Manual Review
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:
Token-Transfer
The text was updated successfully, but these errors were encountered:
All reactions