Reentrancy vulnerability, it is possible for an attacker to re-enter the refund() function and steal funds from the contract.
https://github.com/Cyfrin/2024-12-christmas-dinner/blob/main/src/ChristmasDinner.sol#L137
The refund() function can be re-entered because the nonReentrant modifier never set locked to true.
https://github.com/Cyfrin/2024-12-christmas-dinner/blob/main/src/ChristmasDinner.sol#L77-L81
locked being always false, then require(!locked, "No re-entrancy"); will always go through, leading to a reentrancy vulnerability.
Then refund() can be executed multiple times to steal funds from the contract :
https://github.com/Cyfrin/2024-12-christmas-dinner/blob/main/src/ChristmasDinner.sol#L137C2-L142C6
Re-enter the contract and steal ETH :
- In this example the contract has 10 ETH;
- We first send 2 ETH to the attackerContract (when initializing)
- We choose to steal only 2 ETH as a POC but it can be optimized to drain more from the contract;
Initialize the contract with the target contract address and _amoutETH = 2 ether.
Loss of funds : ETH can be stolen.
Manual review, GitHub, RemixIDE.
Add locked = true; to the nonReentrant modifier :
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.