A reentrancy attack can be carried out in puppyRaffle::refund, because the function does not check for reentrancy and it interacts before updating the storage.
The puppyRaffle contract allows users to get a refund and cancel their participation in the raffle. When a participant calls puppyRaffle::refund with own player index, the function will check that the caller is the address in the index, and then send value via call method to that address. At this point, the callee has control over execution. Since storage hasn't been updated yet (remove player from array), an attacker can call puppyRaffle::refund again, until the puppyRaffle is drained.
This vulnerability causes all funds in the contract to be stolen.
The likelihood of it happening is high, since it is very easy to execute.
To implement the attack, we need to create an attack contract so that it will run code when the external call is made.
We also need to enter that attacking contract's address into the raffle.
Here is a working PoC:
Foundry
Follow CEI pattern - Checks, Effects, Interactions. Update the player array before sending the value:
Another option is to use a nonReentrant modifier from a known library.
reentrancy in refund() function
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.