Skip to content
Request an audit

‹ All findings

odosAssembledData can be manipulated

Crit/HighAutonomint·Sherlock · Hedged stablecoin · 4th December 2024CodebaseH-4

Summary

The signature in withDraw can be reused and this will cause users can choose one improper odosAssembledData and convert less collateral than expected.

Root Cause

In borrowing.sol:withDraw, borrowers can withdraw their collateral. If the current Ether price is larger than deposited Ether price, borrowers will not withdraw all collaterals. There will be some remaining collateral. These remaining collaterals will be swapped to USDT via odos router.

In one normal scenario, the protocol backend server will generate odos assembled data got from odos api, and sign the signature. The borrower will use this signed signature and odosAssembledData to trigger this withDraw function.

But the problem is that malicious users can choose one improper odosAssembledData and signature. Although we can not manipulate the odosAssembledData to any value we want, the backend servers will generate all kinds of odosAssembledData for different borrower's withdrawal. The malicious borrower can choose any odosAssembledData from all of these odosAssembledData.

For example:

  1. Alice deposits WrsETH via depositTokens.
  2. The Ether price increases, Alice wants to withdraw her collateral. Her borrow position's remaining collateral is 0.05 ether. Normally, Alice's odosAssembledData will swap 0.05 ether wrsETH to USDT. But Alice searches the valid used odosAssembledData, and find one odosAssembledData which input token amt is 0.01 ether. Alice uses used odosAssembledData to trigger her withdraw.
  3. We will swap 0.01 ether wrsETH to USDT. This will cause some wrsETH locked in the contract.
solidity
    function _withdraw(
        address toAddress,
        uint64 index,
        bytes memory odosAssembledData,
        uint64 ethPrice, // current ether price
        uint128 exchangeRate,
        uint64 withdrawTime
    ) internal {
    ...
        uint256 amountToSwap = result.collateralRemainingInWithdraw -
            collateralRemainingInWithdraw;
        if (amountToSwap > 0) {
            amountToSwap = (amountToSwap * 1 ether) / exchangeRate;
            treasury.swapCollateralForUSDT(depositDetail.assetName, amountToSwap, odosAssembledData);
        }
    ...    
}

Internal pre-conditions

N/A

External pre-conditions

N/A

Attack Path

  1. Alice deposits WrsETH via depositTokens.
  2. The Ether price increases, Alice wants to withdraw her collateral. Her borrow position's remaining collateral is 0.05 ether. Normally, Alice's odosAssembledData will swap 0.05 ether wrsETH to USDT. But Alice searches the valid used odosAssembledData, and find one odosAssembledData which input token amt is 0.01 ether. Alice uses used odosAssembledData to trigger her withdraw.
  3. We will swap 0.01 ether wrsETH to USDT. This will cause some wrsETH locked in the contract.

Impact

When we swap the remaining collateral to USDT, we may swap only one part of remaining collateral to USDT. This will break our intent. Some remaining collateral will be locked in the contract, and the output USDT is less than expected.

PoC

N/A

Mitigation

odosAssembledData and signature should only be valid for one borrower's specific borrowing index.