Open code423n4 opened 2 years ago
Still working through whether this is an issue we're truly worried about; in particular, if you want to do this, you probably might as well use the 0x API to swap directly.
Nonetheless, it's overshadowed by #37, which will likely lead to changes that will make this impractical as well.
Downgrading to severity 2 as this would lead to "leaked value" as only the fees are lost by the protocol in this attack vector and customer assets aren't being stolen.
Handle
pants
Vulnerability details
Users can call
Swap.swapByQuote()
to execute an ETH swap (where they receive ETH) without paying swap fee for the gained ETH. They can trick the system by settingzrxBuyTokenAddress
to an address of a malicious contract and making it think they have executed an ERC20 swap when they have actually executed an ETH swap. In this case, the system will give them the ETH they got from the swap (boughtETHAmount
) without charging any swap fees for it, because the systems consideres this ETH as "refunded ETH" that wasn't part of the "ERC20" swap.Impact
Users can execute ETH swap without paying swap fees for the ETH the got from the swap.
Proof of Concept
The steps of the attack are:
M
), that will be used forzrxBuyTokenAddress
.Swap.swapByQuote()
withzrxBuyTokenAddress=M
andminimumAmountReceived=0
. The rest of the arguments should specify our ETH swap, nothing special here.M
to return0
and1
at the first and second times whenfillZrxQuote
callszrxBuyTokenAddress.balanceOf(address(this))
, respectively.boughtERC20Amount
now equals1
and the function will "return any refunded ETH" to the caller, without charging any swap fees on it. This ETH is actually the output of that ETH swap.Tool Used
Manual code review.
Recommended Mitigation Steps
Charge swap fees for the "refunded ETH" on ERC20 swaps (when
boughtERC20Amount > 0
), or requireboughtETHAmount == 0
.