DatingDapp

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

# blockProfile Deletes a User's Profile Without Clearing Their LikeRegistry State — Owner Can Permanently Lock Any User's ETH

Root + Impact

Description

  • Describe the normal behavior in one or more sentences

  • Explain the specific issue or problem in one or more sentences

# blockProfile Deletes a User's Profile Without Clearing Their LikeRegistry State — Owner Can Permanently Lock Any User's ETH
## Root + Impact
### Description
The `SoulboundProfileNFT.blockProfile(address user)` function sets `profileToToken[user] = 0` and burns the user's NFT. However, it never notifies `LikeRegistry` to clean up the user's pending likes and balances. After being blocked, the user fails the `require(profileToToken[liked] != 0)` check in `likeUser`, meaning no one can ever like them back. Any ETH already paid by the blocked user is permanently trapped in `userBalances` with no match possible.
### Risk
* **Impact**: Medium - Seizure and permanent locking of user assets without any recovery option.
* **Likelihood**: High - Admin actions directly corrupt dependent child states across external contract modules.
---
## Proof of Concept
The test scenario below demonstrates how a user's funds become permanently inaccessible after a blocking action occurs. When Bob attempts to reciprocate a match request to form a profile connection, the validation pipeline reverts, locking Alice's capital within the deployment balance parameters permanently.
```solidity
function test_OwnerBlocksUser_LocksFundsForever() public {
// Alice and Bob mint profiles
vm.prank(alice);
profileNFT.mintProfile("Alice", 25, "hash");
vm.prank(bob);
profileNFT.mintProfile("Bob", 28, "hash");
// Alice likes Bob with 1 ETH
vm.deal(alice, 1 ether);
vm.prank(alice);
likeRegistry.likeUser{value: 1 ether}(bob);
// Owner blocks Alice
vm.prank(owner);
profileNFT.blockProfile(alice);
// Bob tries to like Alice back — REVERTS (Alice has no profile)
vm.deal(bob, 1 ether);
vm.prank(bob);
vm.expectRevert();
likeRegistry.likeUser{value: 1 ether}(alice);
// Alice's 1 ETH is permanently stuck — no match possible
assertEq(address(likeRegistry).balance, 1 ether);
}
```
---
## Recommended Mitigation
In `blockProfile`, call a cleanup function on `LikeRegistry` that refunds any pending ETH to the blocked user before removing their profile.
```diff
function blockProfile(address user) external onlyOwner {
+ likeRegistry.cleanupAndRefund(user); // Notify LikeRegistry
// ... existing burn logic
}
```
Root cause in the codebase with @> marks to highlight the relevant section

Risk

Likelihood:

  • Reason 1 // Describe WHEN this will occur (avoid using "if" statements)

  • Reason 2

Impact:

  • Impact 1

  • Impact 2

Proof of Concept

Recommended Mitigation

- remove this code
+ add this code
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge 1 day 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!