code-423n4 / 2024-04-renzo-validation

2 stars 2 forks source link

OD.stakeEthFromQueue() fails to check and fill withdrawBuffer deficit. #339

Closed c4-bot-7 closed 5 months ago

c4-bot-7 commented 5 months ago

Lines of code

https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/Deposits/DepositQueue.sol#L187-L206

Vulnerability details

Impact

WithdrawBufferTarget is set by protocol admin to ensure that, at least certain amount should be available for withdrawal.

To ensure availability of funds for withdrawal, withdrawBuffer deficit is checked before every deposit to OD, and filled up when necessary.

However, there was an instance that was not put into consideration which could lead to depositing all available Eth and leaving withdrawBuffer deficit unfilled, thereby making the amount of Eth that should have been available for withdraw not available.

If there is a withdrawBuffer deficit when an admin is calling the stakeEthFromQueue() function, all available Eth could be used and there won't be enough Eth(Eth buffer amount) available for withdraw

Proof of Concept

Instance;

If ethWithdrawBufferTarget was set to 10_ETH, and at the time of admin calling DQ.stakeEthFromQueue withdrewBuffer deficit was 10_ETH(that is, there is zero amount of Eth available for withdrawal at the moment), all available Eth will still be sent to OD.deposit through DQ.stakeEthFromQueueMulti without filling up buffer deficit.

 /// @dev Function called by ETH Restake Admin to start the restaking process in Native ETH
    /// Only callable by a permissioned account
    function stakeEthFromQueue(
        IOperatorDelegator operatorDelegator,
        bytes calldata pubkey,
        bytes calldata signature,
        bytes32 depositDataRoot
    ) external onlyNativeEthRestakeAdmin {
        uint256 gasBefore = gasleft();
        // Send the ETH and the params through to the restake manager
        restakeManager.stakeEthInOperatorDelegator{ value: 32 ether }(
            operatorDelegator,
            pubkey,
            signature,
            depositDataRoot
        );

        emit ETHStakedFromQueue(operatorDelegator, pubkey, 32 ether, address(this).balance);

        // Refund the gas to the Admin address if enough ETH available
        _refundGas(gasBefore);
    }

Tools Used

Manual review.

Recommended Mitigation Steps

Include the call to _checkAndFillETHWithdrawBuffer() within stakeEthFromQueue() and stakeEthFromQueueMulti()

Assessed type

Invalid Validation

raymondfam commented 5 months ago

@howlbot reject

raymondfam commented 5 months ago

It's going to disrupt the 32 ether requirement when triggering eigenPodManager.stake() from OD.