Open code423n4 opened 3 years ago
This exploit was indeed possible when we had the transferFunds
function but now that we have removed it and funds can only be moved by swapYieldSource()
, this exploit is no longer possible since we check for the same depositToken
in _setYieldSource()
.
https://github.com/pooltogether/swappable-yield-source/pull/4
Upgrading to 3 considering the potential for loss of funds
Handle
hickuphh3
Vulnerability details
Impact
transferFunds()
will transfer funds from a specified yield source_yieldSource
to the current yield source set in the contract_currentYieldSource
. However, it fails to check that the deposit tokens are the same. If the specified yield source's assets are of a higher valuation, then a malicious owner or asset manager will be able to exploit and pocket the difference.Proof of Concept
Assumptions:
_yieldSource
has a deposit token of WETH (18 decimals)_currentYieldSource
has a deposit token of DAI (18 decimals)Attacker does the following:
transferFunds(_yieldSource, 100 * 1e18)
_requireDifferentYieldSource()
passes_transferFunds(_yieldSource, 100 * 1e18)
is called_yieldSource.redeemToken(_amount);
→ This will transfer 100 WETH out of the_yieldSource
into the contractuint256 currentBalance = IERC20Upgradeable(_yieldSource.depositToken()).balanceOf(address(this));
→ This will equate to ≥ 100 WETH.require(_amount <= currentBalance, "SwappableYieldSource/transfer-amount-different");
is true since both are100 * 1e18
_currentYieldSource.supplyTokenTo(currentBalance, address(this));
→ This supplies the transferred 100 DAI from step 1 to the current yield sourcetransferERC20(WETH, attackerAddress, 100 * 1e18)
to withdraw 100 WETH out of the contract to the attacker's desired address.Recommended Mitigation Steps
_requireDifferentYieldSource()
should also verify that the yield sources' deposit token addresses are the same.