DatingDapp

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

Multiple Matching Vulnerability in LikeRegistry Contract

Description

The LikeRegistry contract lacks validation to prevent users from being matched with multiple partners simultaneously. This violates the expected monogamous matching behavior of a dating platform and creates potential for social and financial exploitation

The likeUser function performs a match without checking if either party is already matched:

function likeUser(address liked) external payable {
require(msg.value >= 1 ether, "Must send at least 1 ETH");
require(!likes[msg.sender][liked], "Already liked");
require(msg.sender != liked, "Cannot like yourself");
require(profileNFT.profileToToken(msg.sender) != 0, "Must have a profile NFT");
require(profileNFT.profileToToken(liked) != 0, "Liked user must have a profile NFT");
likes[msg.sender][liked] = true;
emit Liked(msg.sender, liked);
// No check if either user is already matched
if (likes[liked][msg.sender]) {
matches[msg.sender].push(liked);
matches[liked].push(msg.sender);
emit Matched(msg.sender, liked);
matchRewards(liked, msg.sender);
}
}

Lines of code

()

Impact

  • Users can be matched with multiple partners simultaneously

  • Potential for romantic and financial exploitation

  • Financial rewards diluted across multiple matches

  • MultiSig wallet control spread across multiple parties

  • Violation of expected dating platform behavior

  • User creates multiple matches to collect more ETH rewards

Proof of Concept

The following test demonstrates multi-matching vulnerability:

function testMultipleMatches() public {
// Setup
address alice = makeAddr("alice");
address bob = makeAddr("bob");
address charlie = makeAddr("charlie");
address dave = makeAddr("dave");
vm.deal(alice, 5 ether);
vm.deal(bob, 5 ether);
vm.deal(charlie, 5 ether);
vm.deal(dave, 5 ether);
// Create profiles
vm.startPrank(alice);
soulboundNFT.mintProfile("Alice", 25, "ipfs://alice");
vm.stopPrank();
vm.startPrank(bob);
soulboundNFT.mintProfile("Bob", 28, "ipfs://bob");
vm.stopPrank();
vm.startPrank(charlie);
soulboundNFT.mintProfile("Charlie", 30, "ipfs://charlie");
vm.stopPrank();
vm.startPrank(dave);
soulboundNFT.mintProfile("Dave", 27, "ipfs://dave");
vm.stopPrank();
// Alice likes Bob
vm.prank(alice);
likeRegistry.likeUser{value: 1 ether}(bob);
// Bob likes Alice - First match
vm.prank(bob);
likeRegistry.likeUser{value: 1 ether}(alice);
// Charlie likes Alice
vm.prank(charlie);
likeRegistry.likeUser{value: 1 ether}(alice);
// Alice likes Charlie - Second match!
vm.prank(alice);
likeRegistry.likeUser{value: 1 ether}(charlie);
// Dave likes Alice
vm.prank(dave);
likeRegistry.likeUser{value: 1 ether}(alice);
// Alice likes Dave - Third match!!
vm.prank(alice);
likeRegistry.likeUser{value: 1 ether}(dave);
// Verify Alice has three matches
vm.prank(alice);
address[] memory aliceMatches = likeRegistry.getMatches();
assertEq(aliceMatches.length, 3);
assertEq(aliceMatches[0], bob);
assertEq(aliceMatches[1], charlie);
assertEq(aliceMatches[2], dave);
// Each match created a new MultiSig wallet
// ETH rewards split across multiple wallets
// All matches remain active simultaneously
}

Fix Recommendation:

  • Add single match limitation

Tools Used

  • Foundry Testing Framework

  • Manual Review

Updates

Appeal created

n0kto Lead Judge 5 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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