Mystery Box

First Flight #25
Beginner FriendlyFoundry
100 EXP
View results
Submission Details
Severity: medium
Valid

User can send an empty reward to another user in `MysteryBox::transferReward`

Summary

User can send an empty reward to another user. `delete rewardsOwned[msg.sender][_index]` this resets the struct properties in Reward struct and don't delete it from the array of `rewardsOwned[msg.sender]`. For example user1 buy a box, then open it and then transfer it to user2. After that `rewardsOwned[user1][0]` will be `Reward{name: "", value: 0}` because `delete' resets the properties. If use1 tries to transfer again `rewardsOwned[user1][0]` reward it will work, therefore user2 is going to have 2 rewards an one of them is going to be empty (value: 0, name: "").

Impact

User can have many empty rewards and when tries to invoke `MysteryBox::claimAllRewards` function, the amount of gas user has to pay will be much bigger because `MysteryBox::claimAllRewards` function loops trough all rewards of an user.

Tools Used

Proof of concept using solidity and foundry. Add the following in TestMysteryBox.t.sol

:

```javascript
function testTransferRewards_AddEmptyReward() public {
vm.deal(user1, 0.1 ether);
vm.startPrank(user1);
mysteryBox.buyBox{value: 0.1 ether}();
mysteryBox.openBox();
mysteryBox.transferReward(user2, 0);
vm.stopPrank();
uint256 expectedRewardsLength = 1;
vm.prank(user2);
uint256 actualRewardsLength = mysteryBox.getRewards().length;
assertEq(actualRewardsLength, expectedRewardsLength);
// try to add an empty reward to user2
vm.startPrank(user1);
mysteryBox.transferReward(user2, 0);
vm.stopPrank();
vm.prank(user2);
uint256 actualRewardsLength2 = mysteryBox.getRewards().length;
assert(actualRewardsLength2 != expectedRewardsLength);
}
```

Recommendations

```diff
+ uint256 rewardsLength = rewardsOwned[msg.sender].length;
+ if (rewardsLength > 0 && rewardsLength - 1 != _index) {
+ uint256 lastRewardIndex = rewardsLength - 1;
+ Reward memory temp = rewardsOwned[msg.sender][lastRewardIndex];
+ rewardsOwned[msg.sender][lastRewardIndex] = rewardsOwned[msg.sender][_index];
+ rewardsOwned[msg.sender][_index] = temp;
+ }
+ rewardsOwned[msg.sender].pop();
- delete rewardsOwned[msg.sender][_index];
```
Updates

Lead Judging Commences

inallhonesty Lead Judge
about 1 year ago

Appeal created

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

A user can poison the `rewardsOwned` of another user via `transferReward` of an empty reward index

Support

FAQs

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

Give us feedback!