Summary
The OneShot::getRapperStats
doesn't check if the given tokenId exists. If the tokenId doesn't exist it returns with a valid stat which can be misleaded for contracts or dApps that use this function.
For example the RapBattle::getRapperSkill
calculates a higher skill for a non existant token than the minted default.
Vulnerability Details
function testNonExistantTokenSkill() public {
address testUser = makeAddr("Bob");
vm.prank(testUser);
oneShot.mintRapper();
uint256 mintedSkill = rapBattle.getRapperSkill(0);
vm.expectRevert();
oneShot.ownerOf(1);
uint256 nonExistantSkill = rapBattle.getRapperSkill(1);
console.log('Minted token default skill: ', mintedSkill);
console.log('Non existant token skill: ', nonExistantSkill);
assert(nonExistantSkill > mintedSkill);
}
Result
forge test -vv --match-test testNonExistantTokenSkill
[⠢] Compiling...
[⠘] Compiling 1 files with 0.8.23
[⠃] Solc 0.8.23 finished in 1.51s
Compiler run successful!
Running 1 test for test/OneShotTest.t.sol:RapBattleTest
[PASS] testNonExistantTokenSkill() (gas: 129246)
Logs:
Minted token default skill: 50
Non existant token skill: 65
Test result: ok. 1 passed; 0 failed; 0 skipped; finished in 5.33ms
Ran 1 test suites: 1 tests passed, 0 failed, 0 skipped (1 total tests)
Impact
Non existant token has higher skill than a minted token.
Tools Used
Manual review, Foundry
Recommendations
Check if the token exists in the OneShot::getRapperStats
function.
function getRapperStats(uint256 tokenId) public view returns (RapperStats memory) {
+ require(tokenId < _nextTokenId, "Non existant token");
return rapperStats[tokenId];
}