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

The function RamNFT::mintRamNFT is public and lacks any kind of access control. This results in anyone being able to mint ramNFTs and enter the Dussehra protocol without paying entree fees

[H-4] The function RamNFT::mintRamNFT is public and lacks any kind of access control. This results in anyone being able to mint ramNFTs and enter the Dussehra protocol without paying entree fees.

Description: Participants are meant to enter the protocol and receive an ramNFT via the Dussehra::enterPeopleWhoLikeRam function. The participants has to pay a fee when calling the enterPeopleWhoLikeRam function, which then calls the RamNFT:mintRamNFT to mint a ramNFT, logs the tokenId and adds initialises characteristics linked to the tokenId. The tokenId and characteristics allow people to participate in the event and win half of the collected fees.

However, RamNFT:mintRamNFT lacks any kind of access control. This results in anyone beng able to call the function directly indefinitely, bypassing Dussehra::enterPeopleWhoLikeRam, avoiding paying the entree fee and entering the event an indefinite amount of times.

// note 1: a public function without any modifier.
function mintRamNFT(address to) public {
// note 2: no if or require checks at all.
uint256 newTokenId = tokenCounter++;
_safeMint(to, newTokenId);
Characteristics[newTokenId] = CharacteristicsOfRam({
ram: to,
isJitaKrodhah: false, //
isDhyutimaan: false, //
isVidvaan: false, //
isAatmavan: false, //
isSatyavaakyah: false //
});
}

Impact: Participants can enter the event for free, while still being able to win half of the collected entree fees. It takes away any incentive to pay the entree fee, leaving the contract without any funds to pay the winning Ram. It breaks the intended functionality of the protocol.

Proof of Concept:

  1. A malicious user calls mintRamNFT 9999 times. Does not pay any entree fees.

  2. mintRamNFT does not revert.

  3. Organiser calls choosingRam::selectRamIfNotSelected.

  4. The malicious user has a very high chance of being selected Ram.

Proof of Concept

Place the following in the CounterTest contract in the Dussehra.t.sol test file.

function test_mintingFreeRamNFTs() public participants {
// let's enter the Ram even 9999 times...
uint256 amountRamNFTstoMint = 9999;
vm.startPrank(player3);
for (uint256 i; i < amountRamNFTstoMint; i++) {
ramNFT.mintRamNFT(player3);
}
vm.stopPrank();
// and then the organiser chooses a Ram
vm.warp(1728691200 + 1);
vm.prank(organiser);
choosingRam.selectRamIfNotSelected();
// it is an almost certainty that player3 will be selected.
vm.assertEq(choosingRam.selectedRam(), player3);
}

Recommended Mitigation: The Dussehra contract needs to be the organiser of the RamNFT contract. This allows the addition of a check that it is the Dussehra contract calling a function.

  1. For clarity, rename organiser to s_ownerDussehra.

  2. Have the Dussehra contract initiate RamNFT. This sets s_ownerDussehra to the address of the Dussehra contract.

  3. Add a check that RamNFT::mintRamNFT can only be called by s_ownerDussehra.

In Dussehra.sol:

+ constructor(uint256 _entranceFee, address _choosingRamContract) {
- constructor(uint256 _entranceFee, address _choosingRamContract, address _ramNFT) {
entranceFee = _entranceFee;
organiser = msg.sender;
+ ramNFT = new RamNFT();
- ramNFT = RamNFT(_ramNFT);
choosingRamContract = ChoosingRam(_choosingRamContract);
}

In RamNFT.sol:

+ error RamNFT__NotDussehra();
.
.
.
- address public organiser;
+ address immutable i_ownerDussehra;
.
.
.
constructor() ERC721("RamNFT", "RAM") {
tokenCounter = 0;
- organiser = msg.sender;
+ i_ownerDussehra = msg.sender;
}
.
.
.
function mintRamNFT(address to) public {
+ if (msg.sender != i_ownerDussehra) {
+ revert RamNFT__NotDussehra();
+ }
uint256 newTokenId = tokenCounter++;
_safeMint(to, newTokenId);
Updates

Lead Judging Commences

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

mintRamNFT is public

Support

FAQs

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