DatingDapp

AI First Flight #6
Beginner FriendlyFoundrySolidityNFT
EXP
View results
Submission Details
Severity: medium
Valid

Missing ETH Refund When Admin Blocks Dating Profiles

Summary

In this dating platform, users invest 1 ETH to "like" other profiles, but when an admin blocks a profile using blockProfile(), all ETH invested in relation to that profile becomes permanently locked in the contract. This includes both the ETH spent by others liking the blocked profile and the ETH the blocked user spent liking others.

contract SoulboundProfileNFT {
mapping(address => uint256) public profileToToken;
function blockProfile(address blockAddress) external onlyOwner {
uint256 tokenId = profileToToken[blockAddress];
require(tokenId != 0, "No profile found");
// Burns NFT without any fund consideration
_burn(tokenId);
delete profileToToken[blockAddress];
delete _profiles[tokenId];
emit ProfileBurned(blockAddress, tokenId);
// No mechanism to:
// 1. Notify LikeRegistry of profile removal
// 2. Handle pending matches
// 3. Refund likes
// 4. Clear like history
}
}

Impact

  • Multiple users could be affected per blocked profile

  • Users who liked blocked profile lose 1 ETH per like

  • UserBalances remain unchanged but inaccessible

  • Users lose funds through no fault of their own

  • Admin could block profiles to deliberately lock funds

Proof of Concept

Recommended Mitigation

When a user is blocked there should be a mechanism to refund users who liked the blocked profile and another mechnism to refund the user that was blocked.
contract LikeRegistry {
function handleProfileBlocked(address blockedUser) external onlyProfileNFT {
// Refund users who liked the blocked profile
for (uint i = 0; i < likersList[blockedUser].length; i++) {
address liker = likersList[blockedUser][i];
if (likes[liker][blockedUser]) {
payable(liker).transfer(1 ether);
likes[liker][blockedUser] = false;
emit LikeRefunded(liker, blockedUser, 1 ether);
}
}
// Refund blocked user's likes
uint256 userRefund = userBalances[blockedUser];
if (userRefund > 0) {
userBalances[blockedUser] = 0;
payable(blockedUser).transfer(userRefund);
emit BlockedUserRefunded(blockedUser, userRefund);
}
}
}
​contract SoulboundProfileNFT {
function blockProfile(address blockAddress) external onlyOwner {
// First handle funds in LikeRegistry
+ likeRegistry.handleProfileBlocked(blockAddress);
// Then proceed with profile removal
uint256 tokenId = profileToToken[blockAddress];
_burn(tokenId);
delete profileToToken[blockAddress];
delete _profiles[tokenId];
emit ProfileBurned(blockAddress, tokenId);
}
}
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 3 hours ago
Submission Judgement Published
Validated
Assigned finding tags:

[M-03] App owner can have users' funds locked by blocking them

## Description App owner can block users at will, causing users to have their funds locked. ## Vulnerability Details `SoulboundProfileNFT::blockProfile` can block any app's user at will. ```js /// @notice App owner can block users 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); } ``` ## Proof of Concept The following code demonstrates the scenario where the app owner blocks `bob` and he is no longer able to call `LikeRegistry::likeUser`. Since the contract gives no posibility of fund withdrawal, `bob`'s funds are now locked. Place `test_blockProfileAbuseCanCauseFundLoss` in `testSoulboundProfileNFT.t.sol`: ```js function test_blockProfileAbuseCanCauseFundLoss() public { vm.deal(bob, 10 ether); vm.deal(alice, 10 ether); // mint a profile NFT for bob vm.prank(bob); soulboundNFT.mintProfile("Bob", 25, "ipfs://profileImage"); // mint a profile NFT for Alice vm.prank(alice); soulboundNFT.mintProfile("Alice", 25, "ipfs://profileImage"); // alice <3 bob vm.prank(alice); likeRegistry.likeUser{value: 1 ether}(bob); vm.startPrank(owner); soulboundNFT.blockProfile(bob); assertEq(soulboundNFT.profileToToken(msg.sender), 0); vm.startPrank(bob); vm.expectRevert("Must have a profile NFT"); // bob is no longer able to like a user, as his profile NFT is deleted // his funds are effectively locked likeRegistry.likeUser{value: 1 ether}(alice); } ``` And run the test: ```bash $ forge test --mt test_blockProfileAbuseCanCauseFundLoss Ran 1 test for test/testSoulboundProfileNFT.t.sol:SoulboundProfileNFTTest [PASS] test_blockProfileAbuseCanCauseFundLoss() (gas: 326392) Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.42ms (219.63µs CPU time) Ran 1 test suite in 140.90ms (1.42ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests) ``` ## Impact App users can have their funds locked, as well as miss out on potential dates. ## Recommendations Add a voting mechanism to prevent abuse and/or centralization of the feature.

Support

FAQs

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

Give us feedback!