Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

duc - SGLLeverage.sellCollateral calls _repay with the skim parameter set to false. #60

Closed
sherlock-admin3 opened this issue Mar 15, 2024 · 6 comments
Labels
Duplicate A valid issue that is a duplicate of an issue with `Has Duplicates` label Escalation Resolved This issue's escalations have been approved/rejected Medium A valid Medium severity issue Reward A payout will be made for this issue

Comments

@sherlock-admin3
Copy link
Contributor

sherlock-admin3 commented Mar 15, 2024

duc

high

SGLLeverage.sellCollateral calls _repay with the skim parameter set to false.

Summary

See vulnerability detail.

Vulnerability Detail

In SGLLeverage.sellCollateral function, after collecting assets and depositing them into YieldBox, this function attempt to repay user's loan by using the obtain asset shares.

amountOut = leverageExecutor.getAsset(
    assetId, address(collateral), address(asset), leverageAmount, calldata_.from, calldata_.data
);
uint256 shareOut = yieldBox.toShare(assetId, amountOut, false);

address(asset).safeApprove(address(yieldBox), type(uint256).max);
yieldBox.depositAsset(assetId, address(this), address(this), 0, shareOut);

...

if (shareOwed <= shareOut) {
    _repay(calldata_.from, calldata_.from, false, partOwed);
} else {
    //repay as much as we can
    uint256 partOut = totalBorrow.toBase(amountOut, false);
    _repay(calldata_.from, calldata_.from, false, partOut);
}

However, it calls _repay with the skim parameter set to false, resulting in the user's funds being pulled during the SGLLendingCommon._repay() function. This means that even though the necessary asset shares were collected by the contract, it still attempts to mistakenly pull from the user for repayment.

function _repay(address from, address to, bool skim, uint256 part) internal returns (uint256 amount) {
    ...
    _addTokens(from, to, assetId, share, uint256(totalShare), skim);
    ...
}
function _addTokens(address from, address, uint256 _assetId, uint256 share, uint256 total, bool skim) internal {
    if (skim) {
        if (share > yieldBox.balanceOf(address(this), _assetId) - total) {
            revert TooMuch();
        }
    } else {
        // yieldBox.transfer(from, address(this), _assetId, share);
        bool isErr = pearlmit.transferFromERC1155(from, address(this), address(yieldBox), _assetId, share);
        if (isErr) {
            revert TransferFailed();
        }
    }
}

Impact

If users have enough allowance and balance for Singularity market, they will experience a loss of funds when using SGLLeverage.sellCollateral.

Code Snippet

https://github.com/sherlock-audit/2024-02-tapioca/blob/main/Tapioca-bar/contracts/markets/singularity/SGLLeverage.sol#L141-L146

Tool used

Manual Review

Recommendation

Should call _repay with skim parameter set to true

Duplicate of #139

@github-actions github-actions bot added High A valid High severity issue Duplicate A valid issue that is a duplicate of an issue with `Has Duplicates` label labels Mar 20, 2024
@nevillehuang nevillehuang added Medium A valid Medium severity issue and removed High A valid High severity issue labels Mar 25, 2024
@sherlock-admin3 sherlock-admin3 changed the title Winning Cobalt Barracuda - SGLLeverage.sellCollateral calls _repay with the skim parameter set to false. duc - SGLLeverage.sellCollateral calls _repay with the skim parameter set to false. Mar 31, 2024
@sherlock-admin3 sherlock-admin3 added the Reward A payout will be made for this issue label Mar 31, 2024
@huuducsc
Copy link

huuducsc commented Apr 2, 2024

Escalate
I believe this issue is not a duplicate of #141, since they are very different. Issue #141 represents that the allowance is double-spent in the sellCollateral function. However, this issue describes the vulnerability of calling _repay with the skim parameter set to false, which will pull funds from the user again even when the target funds are already held in this contract. Therefore, if users give an allowance for the Singularity market, users will incur unexpected losses when calling sellCollateral. Thus, this issue should be a high.

@sherlock-admin2
Copy link
Contributor

Escalate
I believe this issue is not a duplicate of #141, since they are very different. Issue #141 represents that the allowance is double-spent in the sellCollateral function. However, this issue describes the vulnerability of calling _repay with the skim parameter set to false, which will pull funds from the user again even when the target funds are already held in this contract. Therefore, if users give an allowance for the Singularity market, users will incur unexpected losses when calling sellCollateral. Thus, this issue should be a high.

You've created a valid escalation!

To remove the escalation from consideration: Delete your comment.

You may delete or edit your escalation comment anytime before the 48-hour escalation window closes. After that, the escalation becomes final.

@sherlock-admin3 sherlock-admin3 added the Escalated This issue contains a pending escalation label Apr 2, 2024
@cvetanovv
Copy link
Collaborator

I tend to agree in part with the escalation. This is not a duplicate of #141, but a duplicate of #139 (and #57, respectively). The root of the problem is the same, the user's funds are mistakenly pulled twice. If we look at issue #57 we can even see that everything is the same, only the functions are different. In one case it is buyCollateral() and in the other sellCollateral().

If I have to make an analogy for why they should be duplicates, imagine that we have buy() and sell() functions. If they don't have slippage protection then we don't write two separate reports but merge them into one issue with a root slippage protection. I think the analogy here is the same as to why #60 is not a duplicate of #141, but a duplicate of #139 and #57.

This is from the Sherlock documentation: "In case the same vulnerability appears across multiple places in different contracts, they can be considered duplicates."

I also think it should remain Medium because the loss is limited only to the allowance the user has.

@cvetanovv
Copy link
Collaborator

Planning to accept the escalation and remove the duplication with #141, but duplicate with #139.

@Evert0x
Copy link

Evert0x commented Apr 10, 2024

Result:
Medium
Duplicate of #139

@sherlock-admin4 sherlock-admin4 removed the Escalated This issue contains a pending escalation label Apr 10, 2024
@sherlock-admin2 sherlock-admin2 added the Escalation Resolved This issue's escalations have been approved/rejected label Apr 10, 2024
@sherlock-admin3
Copy link
Contributor Author

Escalations have been resolved successfully!

Escalation status:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate A valid issue that is a duplicate of an issue with `Has Duplicates` label Escalation Resolved This issue's escalations have been approved/rejected Medium A valid Medium severity issue Reward A payout will be made for this issue
Projects
None yet
Development

No branches or pull requests

7 participants