Beginner FriendlyFoundryNFT
100 EXP
View results
Submission Details
Severity: high
Invalid

Missing checks for defender different from challenger can lead to the user always winning

Summary

Missing checks for defender different from challenger can lead to the user always winning.

Vulnerability Details

There is no checks for defender different from challenger. This allows collusion between competitors.
As a result, a user who owns two RPR can compete with himself and always win.

POC

Put the test excerpt below in `test/OneShotTest.t.sol`
// Test that a user can compete with himself and always win
function testUserVsHimself(uint256 randomBlock) public {
vm.startPrank(user);
oneShot.mintRapper();
oneShot.approve(address(streets), 0);
streets.stake(0);
oneShot.mintRapper();
oneShot.approve(address(streets), 1);
streets.stake(1);
vm.stopPrank();
vm.warp(4 days + 1);
vm.startPrank(user);
streets.unstake(0);
streets.unstake(1);
oneShot.approve(address(rapBattle), 0);
cred.approve(address(rapBattle), 3);
rapBattle.goOnStageOrBattle(0, 3);
oneShot.approve(address(rapBattle), 1);
cred.approve(address(rapBattle), 3);
console.log("User allowance before battle:", cred.allowance(user, address(rapBattle)));
// assert(cred.allowance(user, address(rapBattle)) == 6);
// Change the block number so we get different RNG
vm.roll(randomBlock);
vm.recordLogs();
rapBattle.goOnStageOrBattle(1, 3);
vm.stopPrank();
Vm.Log[] memory entries = vm.getRecordedLogs();
// Convert the event bytes32 objects -> address
address winner = address(uint160(uint256(entries[0].topics[2])));
assert(winner == user);
}

In the terminal, run the following command:

  • forge test --mt testUserVsHimself

Impact

A user can always win his battles.

Tools Used

Manual review

Recommendations

Add a check for defender different from challenger as follows :
File: src/RapBattle.sol
function goOnStageOrBattle(uint256 _tokenId, uint256 _credBet) external {
if (defender == address(0)) {
defender = msg.sender;
defenderBet = _credBet;
defenderTokenId = _tokenId;
emit OnStage(msg.sender, _tokenId, _credBet);
oneShotNft.transferFrom(msg.sender, address(this), _tokenId);
credToken.transferFrom(msg.sender, address(this), _credBet);
} else {
// credToken.transferFrom(msg.sender, address(this), _credBet);
+ require(defender != msg.sender, "RapBattle: Should be different rappers");
_battle(_tokenId, _credBet);
}
}
Updates

Lead Judging Commences

inallhonesty Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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