Skip to content

Latest commit

 

History

History
113 lines (84 loc) · 3.34 KB

File metadata and controls

113 lines (84 loc) · 3.34 KB

Fast Khaki Raccoon

High

Users can drain LeverageManager

Summary

Users can drain LeverageManager due to addLeverage not verifying if our pod is of the same kind as out positionId.

Root Cause

_addLeveragePreCallback not checking if the _pod is the pod we deposited tokens from

https://github.com/sherlock-audit/2025-01-peapods-finance/blob/main/contracts/contracts/lvf/LeverageManager.sol#L81

    function addLeverage(...) external override workflow(true) {
        uint256 _pTknBalBefore = IERC20(_pod).balanceOf(address(this));

        // trasfer the shares here
        IERC20(_pod).safeTransferFrom(_msgSender(), address(this), _pTknAmt);

        _addLeveragePreCallback(
            _msgSender(),
            _positionId,
            _pod,
            IERC20(_pod).balanceOf(address(this)) - _pTknBalBefore,
            _pairedLpDesired,
            _userProvidedDebtAmt,
            _hasSelfLendingPairPod,
            _config
        );
    }


    function _addLeveragePreCallback(...) internal {
        if (_positionId == 0) {
            _positionId = _initializePosition(_pod, _sender, address(0), _hasSelfLendingPairPod);
        } else {
            address _owner = positionNFT.ownerOf(_positionId);
            require(
                _owner == _sender || positionNFT.getApproved(_positionId) == _sender
                    || positionNFT.isApprovedForAll(_owner, _sender),
                "A3"
            );

            _pod = positionProps[_positionId].pod;
        }

Allowing us to:

  1. safeTransferFrom from pod1 some cheap tokens with high amount
  2. Set _positionId as an expensive pod with high value tokens
  3. The the actual pod will be set from out expensive pod _positionId
            _pod = positionProps[_positionId].pod;
  1. But the amount will be from the cheap pod, with high value

Internal Pre-conditions

LeverageManager to hold any funds

External Pre-conditions

No response

Attack Path

  1. User calls addLeverage with a cheap pod and a high _pTknAmt, while using an expensive pod _positionId
  2. addLeverage transfers the assets and calls _addLeveragePreCallback with the cheap pod token amount - IERC20(_pod).balanceOf(address(this)) - _pTknBalBefore,
        _addLeveragePreCallback(
            _msgSender(),
            _positionId,
            _pod,
            IERC20(_pod).balanceOf(address(this)) - _pTknBalBefore,
            _pairedLpDesired,
            _userProvidedDebtAmt,
            _hasSelfLendingPairPod,
            _config
        );
  1. _addLeveragePreCallback verifies if we are the owner of the expensive pod positionId
            address _owner = positionNFT.ownerOf(_positionId);
            require(
                _owner == _sender || positionNFT.getApproved(_positionId) == _sender
                    || positionNFT.isApprovedForAll(_owner, _sender),
                "A3"
            );
  1. Sets the actual pod address to the positionId pod
            _pod = positionProps[_positionId].pod;
  1. We have officially set the expensive pod with a high amount of tokens, which we didn't deposit, we deposited the cheap low value one

Impact

Users being able to drain any and all assets from LeverageManager.

PoC

No response

Mitigation

Verify if the positionId matches the pod tokens.