DatingDapp

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

Blocked Users Can Remint Profiles, Bypassing Restrictions

Summary

The SoulboundProfileNFT contract allows users to mint a soulbound NFT representing their dating profile. If a user is deemed inappropriate, the contract owner can block them via blockProfile(), which burns their profile NFT and removes associated data. However, because profileToToken[blockAddress] is reset to 0, the blocked user can immediately mint a new profile, effectively bypassing the restriction.

Vulnerability Details

The core of the issue lies in the blockProfile() function. When a user is blocked, the function performs the following steps:

function blockProfile(address blockAddress) external onlyOwner {
uint256 tokenId = profileToToken[blockAddress];
require(tokenId != 0, "No profile found");
_burn(tokenId);
delete profileToToken[blockAddress];
delete _profiles[tokenId];
emit ProfileBurned(blockAddress, tokenId);
}

The function removes all traces of the blocked user’s profile, but it does not store any indication that the user was previously blocked. The mapping profileToToken[blockAddress] is deleted, which resets the condition used to check if a user already has a profile. This allows the user to bypass the restriction in mintProfile():

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);
_profiles[tokenId] = Profile(name, age, profileImage);
profileToToken[msg.sender] = tokenId;
emit ProfileMinted(msg.sender, tokenId, name, age, profileImage);
}

Since profileToToken[msg.sender] has been reset to 0 after blocking, the require() condition no longer prevents reminting. This means that a blocked user can immediately call mintProfile() and create a new dating profile, rendering the blocking mechanism ineffective.

proof of concept

function testBlockedUserCanRemintProfile() public {
vm.prank(user);
soulboundNFT.mintProfile("Alice", 25, "ipfs://profileImage");
uint256 tokenId = soulboundNFT.profileToToken(user);
assertEq(tokenId, 1, "Token should exist before blocking");
// Block the user
vm.prank(owner);
soulboundNFT.blockProfile(user);
uint256 newTokenId = soulboundNFT.profileToToken(user);
assertEq(newTokenId, 0, "Token should be removed after blocking");
// Attempt to mint again
vm.prank(user);
soulboundNFT.mintProfile("Alice 2.0", 26, "ipfs://newProfileImage");
uint256 remintedTokenId = soulboundNFT.profileToToken(user);
assertEq(remintedTokenId, 2, "User should be able to mint a new profile after being blocked");
}

Impact

This vulnerability significantly weakens the protocol’s ability to enforce bans. Malicious users, scammers, or banned individuals can:

  • Create multiple accounts even after being blocked.

  • Avoid accountability by simply reminting new profiles under a different name.

  • Engage in repeated bad behavior, making moderation difficult.

Tools Used

manual review

Recommendations

To prevent blocked users from reminting, the protocol should implement a blacklist mapping that permanently records blocked addresses. Modify blockProfile() as follows:

mapping(address => bool) public blacklisted;
function blockProfile(address blockAddress) external onlyOwner {
uint256 tokenId = profileToToken[blockAddress];
require(tokenId != 0, "No profile found");
_burn(tokenId);
delete profileToToken[blockAddress];
delete _profiles[tokenId];
blacklisted[blockAddress] = true; // Mark user as permanently blocked
emit ProfileBurned(blockAddress, tokenId);
}

Modify mintProfile() to enforce the blacklist:

require(!blacklisted[msg.sender], "User is blocked from minting");
require(profileToToken[msg.sender] == 0, "Profile already exists");
Updates

Appeal created

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

finding_blocked_user_can_recreate_a_profil

Likelihood: Low, any blocked users. Impact: High, not really blocked.

Support

FAQs

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