Platform: Code4rena
Start Date: 11/11/2022
Pot Size: $36,500 USDC
Total HM: 5
Participants: 62
Period: 3 days
Judge: berndartmueller
Id: 181
League: ETH
Rank: 14/62
Findings: 1
Award: $612.43
🌟 Selected for report: 0
🚀 Solo Findings: 0
612.4275 USDC - $612.43
https://github.com/code-423n4/2022-11-non-fungible/blob/main/contracts/Exchange.sol#L168-L210
The contract Exchange.sol has execute()
function which can be called by anyone to execute a single buy and sell order. The function calls _execute()
then _returnDust()
. The latter sends the unrequired ether back to the caller. However, a malicious actor could steal this ether amount from the caller via a cross-functional re-entercy to bulkExecute()
.
Actors:
_execute()
.A scenario as an example:
In the following scenario, the buyer could possibly be the bad actor (in each step I added the value of the state variable remainingETH which is updated by setupExecution
modifier):
execute()
with two matched order that has a POOL payment or WETH, and a msg.value = 1 ether.
execute()
calls _execute()
._execute()
is being executed till it reaches _executeTokenTransfer()
which transfers the token to the buyer.
onERC721Received()
that calls bulkExecute()
with empty executions array and a msg.value > 0. Let's assume it is 0.1 ether.
bulkExecute()
will pass the for-loop and calls _returnDust()
._returnDust()
checks the remainingETH variable is greater than zero (which is 0.1 ether) and sends all the contract's balance to the msg.sender.setupExecution
modifier.
execute()
which calls _returnDust()
after _execute()
is done._returnDust()
checks the remainingETH variable is actually zero so it doesn't send anything to the caller.Note: a similiar scenario could be done by any Fee Recipient by re-entering bulkExecute()
from the receive callback when the payment is ether (paymentToken == address(0))
Manual analysis
Add the reentrancyGuard
modifier to bulkExecute()
function.
function bulkExecute(Execution[] calldata executions) external payable whenOpen setupExecution reentrancyGuard { }
Hint: It is not recommended to perform a state change in modifiers (which is done for example in setupExecution) as it violates the Checks-Effects-Interactions pattern. Please consider moving the logic in setupExecution to a regular function.
#0 - trust1995
2022-11-14T22:26:47Z
Dup of #184
#1 - c4-judge
2022-11-16T14:17:12Z
berndartmueller marked the issue as duplicate of #96
#2 - c4-judge
2022-11-16T14:17:18Z
berndartmueller marked the issue as satisfactory