Steadefi

Steadefi
DeFiHardhatFoundryOracle
35,000 USDC
View results
Submission Details
Severity: high
Valid

Depositor can block entire GMXVault

Summary

Attacker can block entire GMXVault in case if deposit is going to be canceled.

Vulnerability Details

The architecture if steadefi protocol is implemented in such way, that all requests are executed one by one and in order to be finished they need at least 2 steps. That's why system has states, which can be changed only by specific actions. In case if transition is blocked, then whole protocol is blocked. In order to receive requests from GMX protocol, Steadefi has GMXCallback contract, which has implemented all needed hooks. The call of those callbacks signals contract about some action for the specific deposits/withdraws and what is important in case if hook execution reverts, then GMX call doesn't revert.

When user wants to deposit into GMXVault then he can call deposit function. This function will then call GMXDeposit.deposit which will prepare deposit and then execute it. Also function will set Deposit state. This means that now protocol waits, when GMX keeper will execute this deposit and call afterDepositExecution or afterDepositCancellation callback.

In case if deposit will fail on GMX, then afterDepositCancellation hook is called and GMXDeposit.processDepositCancellation function is called.
This means that Steadefi should return all funds to the depositor.
https://github.com/Cyfrin/2023-10-SteadeFi/blob/main/contracts/strategy/gmx/GMXDeposit.sol#L207-L217

if (self.depositCache.depositParams.token == address(self.WNT)) {
self.WNT.withdraw(self.WNT.balanceOf(address(this)));
(bool success, ) = self.depositCache.user.call{value: address(this).balance}("");
require(success, "Transfer failed.");
} else {
// Transfer requested withdraw asset to user
IERC20(self.depositCache.depositParams.token).safeTransfer(
self.depositCache.user,
self.depositCache.depositParams.amt
);
}

As you can see, in case if depositParams.token is native token, then protocol withdraws native tokens and sends them directly to the recipient. In case if this call will revert, that means that protocol will not change state to Open and will be blocked.

This state can be received maliciously: when attacker will revert on transfer(or use whole gas); or it can even be received without bad motive, when contract can't handle transfers of native tokens.

Impact

Protocol is fully blocked

Tools Used

VsCode

Recommendations

In case of native tokens, just send them wrapped. Then no one can grief gas or revert. Another option can be send fixed amount of gas to the transfer call and not revert on failure.

Updates

Lead Judging Commences

hans Lead Judge almost 2 years ago
Submission Judgement Published
Validated
Assigned finding tags:

DOS by rejecting native token

Impact: High Likelihood: High An attacker can repeatedly force the protocol to get stuck in a not-open status. This can happen on both deposit, withdraw callback for both successful execution and failures. Will group all similar issues.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.