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

Slashing may sometimes fail for stETH vaults due to its 1-2 wei corner problem #56

Closed
howlbot-integration bot opened this issue Aug 1, 2024 · 5 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 primary issue Highest quality submission among a set of duplicates 🤖_primary AI based primary recommendation sponsor disputed Sponsor cannot duplicate the issue, or otherwise disagrees this is an issue sufficient quality report This report is of sufficient quality unsatisfactory does not satisfy C4 submission criteria; not eligible for awards

Comments

@howlbot-integration
Copy link

Lines of code

https://github.com/code-423n4/2024-07-karak/blob/f5e52fdcb4c20c4318d532a9f08f7876e9afb321/src/SlashingHandler.sol#L56

Vulnerability details

Impact

Slashing stETH vaults may sometimes fail and always revert due to its innate 1-2 wei corner issue.

Proof of Concept

  1. Context

The protocol plans on working with all ERC20 tokens, and that includes stETH. stETH however, has intrinsic rounding down problems. It's a known issue, and the stETH balance of an account could be lower of 1-2 wei because of rounding down. As such the amount received during transfer can be short 1 or 2 wei. This isn't much, but in context of slashing, in which an amount is transferred from the vault is also expected to be the amount transferred to address(0), this can mean unexpected failure of the handleSlashing function, potentially dossing/delaying slashing of malicious operators.

  1. Bug Location

In SlashingHandler.sol, we see the handleSlashing function. The function transfers the amount of tokens to slash from the vault to the handler. After, the function attempts to transfer the "same" amount address(0).

    function handleSlashing(IERC20 token, uint256 amount) external {
        if (amount == 0) revert ZeroAmount();
        if (!_config().supportedAssets[token]) revert UnsupportedAsset();

        SafeTransferLib.safeTransferFrom(address(token), msg.sender, address(this), amount);
        // Below is where custom logic for each asset lives
        SafeTransferLib.safeTransfer(address(token), address(0), amount);
    }
  1. Final effect
    As explained that the amount received during transfer can be 1 or 2 wei shorter, the function's attempt to send the same amount fails and slashing is not completed.

  2. Runnable POC

The gist link below contains modifications of some of the provided tests, including a mock token that simulates stETH losing 1 wei upon transfers, and instructions on how to run them.

https://gist.github.com/ZanyBonzy/033ee1ca8aae4969a676d8ce83a68c9d

The expected should look like this with an error that reads ERC20InsufficientBalance
img

Tools Used

Manual Review

Recommended Mitigation Steps

Recommend querying token balances before and after every transfer, and transferring the difference between them instead.

Assessed type

Token-Transfer

@howlbot-integration howlbot-integration bot added 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value 🤖_primary AI based primary recommendation bug Something isn't working primary issue Highest quality submission among a set of duplicates sufficient quality report This report is of sufficient quality labels Aug 1, 2024
howlbot-integration bot added a commit that referenced this issue Aug 1, 2024
@devdks25 devdks25 self-assigned this Aug 1, 2024
@c4-sponsor
Copy link

@devdks25 Sponsors are not allowed to close, reopen, or assign issues or pull requests.

@devdks25
Copy link

devdks25 commented Aug 1, 2024

Rebasing tokens aren't supported by the vaults. @dewpe

@dewpe
Copy link

dewpe commented Aug 4, 2024

This issue is taken care of by the transferAmount = Math.min(totalAssets(), totalAssetsToSlash); on L198 of the Vault.sol because both the balanceOf and transfer functions of the stETH vanilla contract call getPooledEthByShares underneath so they both would have the 1-2 gwei rounding issue. The Math.min would then account for the 1-2 gwei underflow

@devdks25 devdks25 added sponsor acknowledged Technically the issue is correct, but we're not going to resolve it for XYZ reasons sponsor disputed Sponsor cannot duplicate the issue, or otherwise disagrees this is an issue and removed sponsor acknowledged Technically the issue is correct, but we're not going to resolve it for XYZ reasons labels Aug 5, 2024
@MiloTruck
Copy link

Invalid.

Under the hood, stETH's transfer() functions calculates the amount of shares to transfer with getSharesByPooledEth():

function getSharesByPooledEth(uint256 _ethAmount) public view returns (uint256) {
    return _ethAmount
        .mul(_getTotalShares())
        .div(_getTotalPooledEther());
}

For the second transfer to revert, getSharesByPooledEth(amount) in the second transfer has to be less than getSharesByPooledEth(amount) in the first. However, as _ethAmount, _getTotalShares() and _getTotalPooledEther() are the same for both transfers, the amount of shares transferred will be the same. It is not possible for the second transfer to revert.

If the warden believes otherwise, consider providing a PoC that forks mainnet and actually interacts with stETH.

@c4-judge c4-judge added the unsatisfactory does not satisfy C4 submission criteria; not eligible for awards label Aug 11, 2024
@c4-judge
Copy link
Contributor

MiloTruck marked the issue as unsatisfactory:
Invalid

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 primary issue Highest quality submission among a set of duplicates 🤖_primary AI based primary recommendation sponsor disputed Sponsor cannot duplicate the issue, or otherwise disagrees this is an issue sufficient quality report This report is of sufficient quality unsatisfactory does not satisfy C4 submission criteria; not eligible for awards
Projects
None yet
Development

No branches or pull requests

5 participants