DatingDapp

AI First Flight #6
Beginner FriendlyFoundrySolidityNFT
EXP
View results
Submission Details
Impact: high
Likelihood: high
Invalid

Likes Persist After Profile Burn/Block: Stale State Enables Unintended Matches

Root + Impact

Description

When a profile is burned (via burnProfile() or blockProfile()), the
likes mapping in LikeRegistry is NOT cleared. If the user re-mints a
new profile, their old likes still exist. This means:

  1. A blocked user can re-mint and instantly match with anyone who previously
    liked them — bypassing the block entirely.

  2. A user who burned and re-created their profile carries stale like state.

// src/SoulboundProfileNFT.sol:57-66 — blockProfile only cleans NFT state
function blockProfile(address blockAddress) external onlyOwner {
uint256 tokenId = profileToToken[blockAddress];
require(tokenId != 0, "No profile found");
_burn(tokenId);
delete profileToToken[blockAddress];
delete _profiles[tokenId];
// @> likes[blockedUser][...] in LikeRegistry are NOT cleared
// @> likes[...][blockedUser] in LikeRegistry are NOT cleared
}

Risk

Likelihood: Medium

  • Requires a user to burn/be blocked and then re-mint

  • Blocked users are motivated to re-mint to recover match state

Impact: High

  • Blocked users bypass safety measures and can still match

  • Users unknowingly match with previously-blocked accounts

  • Stale likes can trigger matches with profiles the user no longer intends

Proof of Concept

This step-by-step scenario proves that a blocked user can re-mint and
exploit stale like data from a previous profile to instantly trigger a
match — completely bypassing the owner's moderation action.

// 1. Alice likes Bob (likes[Alice][Bob] = true)
// 2. Owner blocks Bob (blockProfile(Bob)) — Bob's NFT burned
// 3. Bob re-mints a new profile (mintProfile works, profileToToken was deleted)
// 4. Bob calls likeUser(Alice) — passes all checks (both have profiles)
// 5. likes[Alice][Bob] is STILL true from step 1
// 6. Match triggers instantly — Bob matched despite being blocked

Recommended Mitigation

Introduce a persistent blocklist so blocked addresses cannot re-create
profiles, or implement cross-contract cleanup of stale likes when a
profile is destroyed.

Option A — Prevent re-minting for blocked addresses:

+ mapping(address => bool) public isBlocked;
function blockProfile(address blockAddress) external onlyOwner {
// ...
+ isBlocked[blockAddress] = true;
}
function mintProfile(...) external {
+ require(!isBlocked[msg.sender], "Address is blocked");
require(profileToToken[msg.sender] == 0, "Profile already exists");
// ...
}

Option B — Clear likes in LikeRegistry when a profile is destroyed
(requires cross-contract coordination or event-driven cleanup).

Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 3 hours ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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

Give us feedback!