MorpheusAI

MorpheusAI
Foundry
22,500 USDC
View results
Submission Details
Severity: low
Invalid

Tokens are approved to the maximum value of `type(uint256)`

Summary

The L1Sender and L2TokenReceiver set unlimitted approval of tokens. That can lead to a significant financial loss.

Vulnerability Details

The L1Sender::L1Sender__initfunction calls L1Sender::setDepositTokenConfig that calls the functions L1Sender::_replaceDepositToken and L1Sender::_replaceDepositTokenGateway. The last two functions make approve of maximum value of type uint256 for unwrappedToken_ and newToken_:

function _replaceDepositToken(address oldToken_, address newToken_) private {
bool isTokenChanged_ = oldToken_ != newToken_;
if (oldToken_ != address(0) && isTokenChanged_) {
// Remove allowance from stETH to wstETH
IERC20(unwrappedDepositToken).approve(oldToken_, 0);
}
if (isTokenChanged_) {
// Get stETH from wstETH
address unwrappedToken_ = IWStETH(newToken_).stETH();
// Increase allowance from stETH to wstETH. To exchange stETH for wstETH
@> IERC20(unwrappedToken_).approve(newToken_, type(uint256).max);
unwrappedDepositToken = unwrappedToken_;
}
}
function _replaceDepositTokenGateway(
address oldGateway_,
address newGateway_,
address oldToken_,
address newToken_
) private {
bool isAllowedChanged_ = (oldToken_ != newToken_) || (oldGateway_ != newGateway_);
if (oldGateway_ != address(0) && isAllowedChanged_) {
IERC20(oldToken_).approve(IGatewayRouter(oldGateway_).getGateway(oldToken_), 0);
}
if (isAllowedChanged_) {
@> IERC20(newToken_).approve(IGatewayRouter(newGateway_).getGateway(newToken_), type(uint256).max);
}
}

Also, the L2TokenReceiver::L2TokenReceiver__init calls the function L2TokenReceiver::_editParams that approves the maximum value of type uint256 for tokenIn and tokenOut:

function _editParams(SwapParams memory newParams_) private {
require(newParams_.tokenIn != address(0), "L2TR: invalid tokenIn");
require(newParams_.tokenOut != address(0), "L2TR: invalid tokenOut");
@> TransferHelper.safeApprove(newParams_.tokenIn, router, type(uint256).max);
@> TransferHelper.safeApprove(newParams_.tokenIn, nonfungiblePositionManager, type(uint256).max);
@> TransferHelper.safeApprove(newParams_.tokenOut, nonfungiblePositionManager, type(uint256).max);
params = newParams_;
}

These unlimited allowances can lead to a significant financial loss.

Impact

The L1Sender contract sets an unlimited allowance for the IGatewayRouter contract to spend a ERC20 token on its behalf.
If the IGatewayRouter contract is compromised, this could lead to a loss of all stETH tokens held in the L1Sender contract. The malicious user can call the transferFrom function of the ERC20 token, specifying the L1Sender contract as the from address, their own address as the to address, and the full balance of the L1Sender contract as the amount. Since the allowance is set to type(uint256).max, the ERC20 token contract allows the transfer, and the attacker drains all the tokens from the L1Sender contract.

Also, the L2TokenReceiver::_editParams function sets the approval for tokenIn and tokenOut to the maximum possible value for the router and nonfungiblePositionManager contracts using TransferHelper.safeApprove. This means that these contracts are allowed to transfer an unlimited amount of the tokenIn and tokenOut tokens on behalf of the L2TokenReceiver contract. And again if the router or nonfungiblePositionManager contracts are compromised, a malicious user can exploit them to drain the approved tokens from the L2TokenReceiver contract.

Tools Used

Manual Review

Recommendations

Instead of setting the maximum possible allowance, add a function that set the allowance to the exact amount needed for each transaction. This function should be called before each transfer operation, and it should revoke the previous approval, if there is any, and set a new one for the exact amount to be transferred.

Updates

Lead Judging Commences

inallhonesty Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.