Summary
In the MysteryBox.sol::addReward
function, the new rewards are added to an array rewardPool
. This array is not used anywhere that the user will be able to receive that reward.
Vulnerability Details
When a user has boxes to open and calls openBox
, the rewards they can receive are already hard coded in that function. If the owner calls addReward
and adds new rewards, these will never be receivable by the users.
Impact
No matter how many times openBox
is called, the Diamond Coin reward will never be receivable.
function testNewRewardsCannotBeReceived() public {
vm.prank(owner);
mysteryBox.addReward("Diamond Coin", 2 ether);
MysteryBox.Reward[] memory rewards = mysteryBox.getRewardPool();
assertEq(rewards.length, 5);
assertEq(rewards[4].name, "Diamond Coin");
assertEq(rewards[4].value, 2 ether);
vm.deal(user1, 1 ether);
vm.prank(user1);
mysteryBox.buyBox{value: 0.1 ether}();
console.log("Before Open:", mysteryBox.boxesOwned(user1));
vm.prank(user1);
mysteryBox.openBox();
console.log("After Open:", mysteryBox.boxesOwned(user1));
assertEq(mysteryBox.boxesOwned(user1), 0);
vm.prank(user1);
rewards = mysteryBox.getRewards();
console2.log(rewards[0].name);
assertEq(rewards.length, 1);
}
Tools Used
--Foundry
Recommendations
It is recommended to re-work the openBox
function to use the rewardPool
array when determining which reward the user will receive.
function openBox() public {
require(boxesOwned[msg.sender] > 0, "No boxes to open");
// Generate a random number between 0 and 99
uint256 randomValue = uint256(keccak256(abi.encodePacked(block.timestamp, msg.sender))) % 100;
// Determine the reward based on probability
if (randomValue < 75) {
// 75% chance to get Coal (0-74)
- rewardsOwned[msg.sender].push(Reward("Coal", 0 ether));
+ rewardsOwned[msg.sender].push(rewardPool[0]);
} else if (randomValue < 95) {
// 20% chance to get Bronze Coin (75-94)
- rewardsOwned[msg.sender].push(Reward("Bronze Coin", 0.1 ether));
+ rewardsOwned[msg.sender].push(rewardPool[1]);
} else if (randomValue < 99) {
// 4% chance to get Silver Coin (95-98)
- rewardsOwned[msg.sender].push(Reward("Silver Coin", 0.5 ether));
+ rewardsOwned[msg.sender].push(rewardPool[2]);
} else {
// 1% chance to get Gold Coin (99)
- rewardsOwned[msg.sender].push(Reward("Gold Coin", 1 ether));
+ rewardsOwned[msg.sender].push(rewardPool[3]);
}
boxesOwned[msg.sender] -= 1;
}