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

[WP-H2] ConvexStakingWrapper#deposit() depositors may lose their funds when the _amount is huge #194

Open
code423n4 opened this issue Feb 9, 2022 · 2 comments
Labels
2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working duplicate This issue or pull request already exists

Comments

@code423n4
Copy link
Contributor

Lines of code

https://github.com/code-423n4/2022-02-concur/blob/72b5216bfeaa7c52983060ebfc56e72e0aa8e3b0/contracts/ConvexStakingWrapper.sol#L228-L250

Vulnerability details

When the value of _amount is larger than type(uint192).max, due to unsafe type casting, the recorded deposited amount can be much smaller than their invested amount.

https://github.com/code-423n4/2022-02-concur/blob/72b5216bfeaa7c52983060ebfc56e72e0aa8e3b0/contracts/ConvexStakingWrapper.sol#L228-L250

function deposit(uint256 _pid, uint256 _amount)
    external
    whenNotPaused
    nonReentrant
{
    _checkpoint(_pid, msg.sender);
    deposits[_pid][msg.sender].epoch = currentEpoch();
    deposits[_pid][msg.sender].amount += uint192(_amount);
    if (_amount > 0) {
        IERC20 lpToken = IERC20(
            IRewardStaking(convexPool[_pid]).poolInfo(_pid).lptoken
        );

        lpToken.safeTransferFrom(msg.sender, address(this), _amount);
        lpToken.safeApprove(convexBooster, _amount);
        IConvexDeposits(convexBooster).deposit(_pid, _amount, true);
        lpToken.safeApprove(convexBooster, 0);
        uint256 pid = masterChef.pid(address(lpToken));
        masterChef.deposit(msg.sender, pid, _amount);
    }

    emit Deposited(msg.sender, _amount);
}

PoC

When _amount = uint256(type(uint192).max) + 1:

  • At L235, uint192(_amount) = 0, deposits[_pid][msg.sender].amount = 0;
  • At L241, uint256(type(uint192).max) + 1 will be transferFrom msg.sender.

Expected results:

deposits[_pid][msg.sender].amount == uint256(type(uint192).max) + 1;

Actual results:

deposits[_pid][msg.sender].amount = 0.

The depositor loses all their invested funds.

Recommendation

Consider adding a upper limit for the _amount parameter:

require(_amount <= type(uint192).max, "...");
@code423n4 code423n4 added 3 (High Risk) Assets can be stolen/lost/compromised directly bug Something isn't working labels Feb 9, 2022
code423n4 added a commit that referenced this issue Feb 9, 2022
@r2moon r2moon added the duplicate This issue or pull request already exists label Feb 16, 2022
@r2moon
Copy link
Collaborator

r2moon commented Feb 16, 2022

duplicated with #224

@GalloDaSballo
Copy link
Collaborator

The warden has shown how casting without safe checks can cause the accounting to break and cause end users to loose deposited tokens.

While the finding has merit I believe that because this applies to niche situations, and is conditional on specific inputs, that Medium Severity is more appropriate

@GalloDaSballo GalloDaSballo added 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value and removed 3 (High Risk) Assets can be stolen/lost/compromised directly labels Apr 19, 2022
This was referenced Apr 24, 2022
@JeeberC4 JeeberC4 reopened this Apr 27, 2022
This was referenced Apr 28, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working duplicate This issue or pull request already exists
Projects
None yet
Development

No branches or pull requests

5 participants