Lucene search

K
code423n4Code4renaCODE423N4:2023-06-STADER-FINDINGS-ISSUES-266
HistoryJun 09, 2023 - 12:00 a.m.

Insecure State settleFunds function, state update

2023-06-0900:00:00
Code4rena
github.com
13
vulnerability unauthorizedmanipulation financiallosses improperdistribution timingissue

Lines of code

Vulnerability details

Impact

The impact of this finding is that an unauthorized party can manipulate the state of the vaultSettleStatus variable before executing critical operations related to penalty marking, fund distribution, and reward deposits. This can potentially disrupt the intended flow of funds and rewards, leading to financial losses or improper distribution.

Proof of Concept

// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

// Import contract dependencies and interfaces

contract ValidatorWithdrawalVault {
    bool internal vaultSettleStatus;

    // Other contract functions and variables...

    function settleFunds() external override {
        uint8 poolId = VaultProxy(payable(address(this))).poolId();
        uint256 validatorId = VaultProxy(payable(address(this))).id();
        IStaderConfig staderConfig = VaultProxy(payable(address(this))).staderConfig();
        address nodeRegistry = IPoolUtils(staderConfig.getPoolUtils()).getNodeRegistry(poolId);
        if (msg.sender != nodeRegistry) {
            revert CallerNotNodeRegistryContract();
        }
        (uint256 userSharePrelim, uint256 operatorShare, uint256 protocolShare) = calculateValidatorWithdrawalShare();

        uint256 penaltyAmount = getUpdatedPenaltyAmount(poolId, validatorId, staderConfig);

        if (operatorShare < penaltyAmount) {
            ISDCollateral(staderConfig.getSDCollateral()).slashValidatorSD(validatorId, poolId);
            penaltyAmount = operatorShare;
        }

        uint256 userShare = userSharePrelim + penaltyAmount;
        operatorShare = operatorShare - penaltyAmount;

        // Final settlement
        vaultSettleStatus = true;
        IPenalty(staderConfig.getPenaltyContract()).markValidatorSettled(poolId, validatorId);
        IStaderStakePoolManager(staderConfig.getStakePoolManager()).receiveWithdrawVaultUserShare{value: userShare}();
        UtilLib.sendValue(payable(staderConfig.getStaderTreasury()), protocolShare);
        IOperatorRewardsCollector(staderConfig.getOperatorRewardsCollector()).depositFor{value: operatorShare}(
            getOperatorAddress(poolId, validatorId, staderConfig)
        );
        emit SettledFunds(userShare, operatorShare, protocolShare);
    }
}

Tools Used

Manual review

Recommended Mitigation Steps

move line 75 after IOperatorRewardsCollector(staderConfig.getOperatorRewardsCollector()).depositFor{value: operatorShare}(
getOperatorAddress(poolId, validatorId, staderConfig)
);

IPenalty(staderConfig.getPenaltyContract()).markValidatorSettled(poolId, validatorId);
        IStaderStakePoolManager(staderConfig.getStakePoolManager()).receiveWithdrawVaultUserShare{value: userShare}();
        UtilLib.sendValue(payable(staderConfig.getStaderTreasury()), protocolShare);
        IOperatorRewardsCollector(staderConfig.getOperatorRewardsCollector()).depositFor{value: operatorShare}(
            getOperatorAddress(poolId, validatorId, staderConfig)
        );
vaultSettleStatus = true;

Assessed type

Timing


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

All reactions