DatingDapp

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

Lack of Proper Blocking Mechanism in blockProfile

Summary

The blockProfile function is intended to block a user’s profile but instead permanently deletes it by burning the associated NFT. This allows the blocked user to remint a new profile, bypassing the intended restriction.

Vulnerability Details

The function blockProfile(address blockAddress) allows the contract owner to "block" a user’s profile. However, instead of enforcing a restriction, it:

  • Burns (_burn(tokenId)) the user’s profile NFT.

  • Deletes their profile data (delete profileToToken[blockAddress]).

  • Deletes their stored metadata (delete _profiles[tokenId]).

As a result, the user is not truly blocked; they can call mintProfile again to create a new profile with no restrictions.

Impact

  • Severity: Medium

  • Blocking a user should prevent them from reminting, but this implementation only removes their current profile.

  • Can be abused by malicious actors to continuously recreate profiles.

  • Users who should be blocked remain free to participate in the system.

POC

function testBlockProfileOfOwnerInsteadOfActualBlocking() public {
vm.prank(user);
soulboundNFT.mintProfile("Alice", 25, "ipfs://profileImage");
uint256 tokenId = soulboundNFT.profileToToken(user);
assertEq(tokenId, 1, "Token ID should be 1");
string memory uri = soulboundNFT.tokenURI(tokenId);
assertTrue(bytes(uri).length > 0, "Token URI should be set");
console.log("-------- Before blocking --------");
console.log("profile Token ID: ", tokenId);
vm.prank(owner);
soulboundNFT.blockProfile(user);
console.log("-------- After blocking --------");
console.log("After Token ID: ", tokenId);
vm.prank(user);
soulboundNFT.mintProfile("Alice", 25, "ipfs://profileImage");
uint256 tokenIdNew = soulboundNFT.profileToToken(user);
assertEq(tokenIdNew, 2, "Token ID should be 2");
console.log("-------- Profile Reminted --------");
console.log("New Minted Token ID: ", tokenIdNew);
string memory uri2 = soulboundNFT.tokenURI(tokenIdNew);
assertTrue(bytes(uri2).length > 0, "Token URI should be set");
}
Ran 1 test for test/testSoulboundProfileNFT.t.sol:SoulboundProfileNFTTest
[PASS] testBlockProfileOfOwnerInsteadOfActualBlocking() (gas: 296144)
Logs:
-------- Before blocking --------
profile Token ID: 1
-------- After blocking --------
After Token ID: 1
-------- Profile Reminted --------
New Minted Token ID: 2
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.73ms (736.41µs CPU time)

Tools Used

Manual review of the Solidity code.
Foundry test cases to verify unintended behavior.

Recommendations

Instead of deleting the profile, implement a proper blocking mechanism using a mapping to track blocked users.

Key Fixes:

  1. isBlocked mapping ensures blocked users cannot remint.

  2. notBlocked modifier prevents blocked users from executing mintProfile().

  3. No deletion of profile data—the profile remains in storage if needed for moderation purposes.

mapping(address => bool) public isBlocked;
function blockProfile(address blockAddress) external onlyOwner {
require(profileToToken[blockAddress] != 0, "No profile found");
isBlocked[blockAddress] = true; // Mark user as blocked
emit ProfileBlocked(blockAddress);
}
modifier notBlocked() {
require(!isBlocked[msg.sender], "User is blocked");
_;
}

Add the notBlocked() modifier to the mintProfile function

function mintProfile(string memory name, uint8 age, string memory profileImage) external notBlocked {
Updates

Appeal created

n0kto Lead Judge 5 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.