DatingDapp

First Flight #33
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Severity: medium
Valid

Reentrancy is possible in the `SoungboundProfileNFT::mintProfile` function.

[M-4] Summary

Reentrancy is possible in the SoungboundProfileNFT::mintProfile function.

Vulnerability Details

The mintProfile function is not protected against reentrancy, which could happen via the _safeMint invocation. If the message sender is a contract, which implements the IERC721Receiver.onERC721Received function, this function will be internally invoked as per the ERC721 standard. This could allow the contract to re-enter one of the other functions. For example, re-entering the mintProfile function would allow the message sender to mint multiple profiles with the same address. This would lead to the potential depletion of the tokenId counter, and also incorrect state, as the profileToToken mapping would be overwritten and contain only the last minted tokenId.

Impact

Low impact - the contract state would be corrupted. High likelihood - an attacking contract is really easy to create. For example:

contract MintAttacker is IERC721Receiver {
SoulboundProfileNFT public profileNFT;
constructor(SoulboundProfileNFT _profileNFT) {
profileNFT = _profileNFT;
}
function mintProfile() public {
profileNFT.mintProfile("Attacker", 18, "attacker.png");
}
function onERC721Received(address, address, uint256, bytes calldata) external returns (bytes4) {
profileNFT.mintProfile("Attacker", 18, "attacker.png");
return this.onERC721Received.selector;
}
}

Tools Used

Manual review.

Recommendations

Use a stock reentrancy guard (for example, OpenZeppelin's ReentrancyGuard) or follow the CEI (checks-effects-interactions) pattern. Here's an example of the latter:

function mintProfile(string memory name, uint8 age, string memory profileImage) external {
require(profileToToken[msg.sender] == 0, "Profile already exists");
uint256 tokenId = ++_nextTokenId;
- _safeMint(msg.sender, tokenId);
// Store metadata on-chain
_profiles[tokenId] = Profile(name, age, profileImage);
profileToToken[msg.sender] = tokenId;
emit ProfileMinted(msg.sender, tokenId, name, age, profileImage);
+ _safeMint(msg.sender, tokenId);
}
Updates

Appeal created

n0kto Lead Judge 6 months ago
Submission Judgement Published
Validated
Assigned finding tags:

finding_mintProfile_reentrancy

Likelihood: High, anyone can do it. Impact: Low, several profile will be minted, which is not allowed by the protocol, but only the last one will be stored in profileToToken and won't affect `likeUser` or `matchRewards`.

Support

FAQs

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