DatingDapp

First Flight #33
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Severity: low
Invalid

Soulbound Profile Re-Minting Bypass

Summary

The profileToToken mapping in SoulboundProfileNFT incorrectly allows users to re-mint a new profile NFT after burning their previous one. This flaw results in users bypassing the soulbound nature of the NFT, allowing them to obtain multiple profiles by burning and re-minting, violating profile uniqueness

Vulnerability Details

Root Cause

  • The profileToToken mapping is used to track a user’s NFT token ID.

  • When a user mints a profile, their profileToToken is set to their tokenId.

  • If they burn the profile, their profileToToken is reset to 0.

  • The contract only prevents minting if profileToToken[msg.sender] != 0.

  • Since profileToToken[msg.sender] == 0 after burning, the user can mint again, bypassing restrictions.

POC

copy this test and paste in the testSoulboundProfileNFT.t.soland run it

function test_ProfileToTokenMappingCollision() public {
// Step 1: User mints a profile
vm.prank(user);
soulboundNFT.mintProfile("Alice", 25, "ipfs://profile1");
// Step 2: User burns their profile
vm.prank(user);
soulboundNFT.burnProfile();
// Step 3: Check that profileToToken[user] is reset to 0
assertEq(soulboundNFT.profileToToken(user), 0, "Profile mapping not cleared properly");
// Step 4: User mints a second profile (should not be allowed)
vm.expectRevert("Cannot remint profile");
vm.prank(user);
soulboundNFT.mintProfile("AliceAgain", 26, "ipfs://profile2");
}

The result goes as thus

Ran 1 test for test/testSoulboundProfileNFT.t.sol:SoulboundProfileNFTTest
[FAIL: next call did not revert as expected] test_ProfileToTokenMappingCollision() (gas: 328344)
Suite result: FAILED. 0 passed; 1 failed; 0 skipped; finished in 235.36ms (37.45ms CPU time)

Ran 1 test suite in 5.08s (235.36ms CPU time): 0 tests passed, 1 failed, 0 skipped (1 total tests)

Failing tests:````Encountered 1 failing test in test/testSoulboundProfileNFT.t.sol:SoulboundProfileNFTTest````[FAIL: next call did not revert as expected] test_ProfileToTokenMappingCollision() (gas: 328344)

Encountered a total of 1 failing tests, 0 tests succeeded

Meaning:

  • The test expected the second mintProfile call to revert, but it succeeded instead.

  • This confirms that the mapping collision bug exists—the contract allows a user to mint a second profile after burning the first one.

Impact

  • Users can mint multiple profiles instead of being limited to one.

  • Soulbound NFTs are meant to be non-transferable and one per user. This bug breaks that assumption.

Tools Used

manual review and foundry

Recommendations

  1. The contract needs a hasMintedBefore mapping to track if a user ever minted before

mapping(address => bool) public hasMintedBefore;

2.Modify mintProfile to check this flag

function mintProfile(string memory name, uint8 age, string memory profileImage) external {
require(!hasMintedBefore[msg.sender], "Cannot remint profile"); // Prevents re-minting
uint256 tokenId = _nextTokenId();
_mint(msg.sender, tokenId);
profileToToken[msg.sender] = tokenId;
hasMintedBefore[msg.sender] = true; // Marks user as having minted before
emit ProfileMinted(msg.sender, tokenId, name, age, profileImage);
}
Updates

Appeal created

n0kto Lead Judge 6 months ago
Submission Judgement Published
Invalidated
Reason: Design choice
Assigned finding tags:

invalid_burning_recreating_profile

Design choice to update your age, name and photo. Scam is not a valid impact.

Support

FAQs

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