TokeAutoEthStrategy contract will have its TokeMak reward tokens stuck inside the strategy contract and these tokens won't be sent to the VaultV2 contract as the protocol assumed.
Vulnerability Details
In the _deallocate function below, I will explain why that will be the case:
function_deallocate(uint256amount)internaloverridereturns(uint256){uint256 sharesNeeded = autoEth.convertToShares(amount);uint256 actualSharesHeld = rewarder.balanceOf(address(this));uint256 shareDiff = actualSharesHeld - sharesNeeded;if(shareDiff <=1e18){// account for vault rounding up sharesNeeded = actualSharesHeld;}// withdraw shares, claim any rewards rewarder.withdraw(address(this), sharesNeeded,true);uint256 wethBalanceBefore = TokenUtils.safeBalanceOf(address(weth),address(this)); autoEth.redeem(sharesNeeded,address(this),address(this));uint256 wethBalanceAfter = TokenUtils.safeBalanceOf(address(weth),address(this));uint256 wethRedeemed = wethBalanceAfter - wethBalanceBefore;if(wethRedeemed < amount){emitStrategyDeallocationLoss("Strategy deallocation loss.", amount, wethRedeemed);}require(TokenUtils.safeBalanceOf(address(weth),address(this))>= amount,"Strategy balance is less than the amount needed"); TokenUtils.safeApprove(address(weth),msg.sender, amount);return amount;}
In the Rewarder contract for TokeAuto vaults from the Autopilot protocol, when a user calls the rewarder.withdraw() function, the rewarder contract sends autoETH tokens to the user/caller. It also sends along accumulated TokeMak (TOKE token) portion of reward tokens to the same caller/user.
So, if say the strategy deposits 100 WETH and gets minted x amount of autoETH which then gets staked into the rewarder contract, when a user then calls withdraw on the rewarder contract, the rewarder contract
Sends autoETH requested by the user to the user (these autoETH will then be exchanged to WETH in the redeem() call to autoETH contract)
Sends accumulated unclaimed rewards (TOKE tokens) to the same user
This goes against the assumption of Alchemix because Alchemix assumes and needs these reward tokens to go to the VaultV2 contract this strategy is tied to, not stay inside the strategy contract. As a result, these tokens sent during that withdraw() call will be stuck and cannot be retrieved out of the strategy contract rendering a loss.
For an attacker to make this the case, they can:
Deposit a small amount of assets into the VaultV2 contract tied to this strategy contract
Later, these assets will be allocated to the TokeAutoETHStrategy contract along with other user deposits. Let's assume the attacker deposits 0.5 WETH or 0.1 etc and then other users deposit e.g 10 WETH, 20 WETH etc
After the allocation of these WETH to the strategy contract which then swaps these into autoETH and deposits them into the rewarder contract to earn rewards, the attacker can wait a couple hours and then unstake small amounts from their initial 0.5 WETH deposit.
Doing this, since the VaultV2 will have had all of its WETH allocated to the strategy, the _deallocate call will be triggered for each of his withdrawals and the rewarder.withdraw() function will be triggered which will:
Withdraw x amount of shares that is enough to cover x amount of user requested WETH
Send all accumulated TOKE rewards to the strategy contract instead of the VaultV2 contract
Now, the attacker will be able to aggregate all the accumulated TOKE rewards thus far into the strategy contract and other users who deposited large sums of WETH that were allocated to this strategy will all lose their TOKE portion of yield which cannot be recovered from the strategy contract.
Note: My POC above demonstrates the locked TOKE tokens inside the strategy contract as you can see from the logs:
The revert is from the AutoPool Debt external contract that the Rewarder contract interacts with during forked tests and calls chainlink for prices which is not relevant to this bug but that is the reason for the revert in the end.
Also, note the added detailed log I added to the _deallocate() function in the TokeAutoEthStrategy contract to speed up understanding of the bug:
Impact Details
Complete loss of accumulated TOKE yield everytime the bug I described above in the vulnerability details section gets triggered. Since these reward tokens then get diverted to the strategy contract rather than the VaultV2 contract, they cannot be reclaimed.
From my POC and a 1 month yield gains duration, the locked TOKE tokens would be 35k TOKE which is currently valued at USD 7000 since each TOKE is worth USD 0.2.