DatingDapp

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

mintProfile() accepts any uint8 age including 0 — no minimum age enforcement on a dating platform

Root + Impact

Description

// SoulboundProfileNFT.sol — mintProfile()
function mintProfile(
string memory name,
uint8 age, // @> uint8 — accepts 0 to 255
string memory profileImage
) external {
require(profileToToken[msg.sender] == 0, "Profile already exists");
// @> No minimum age check — age = 0, 1, 5, 17 all accepted
// @> No maximum age check — age = 200, 255 also accepted (nonsensical)
uint256 tokenId = ++_nextTokenId;
_safeMint(msg.sender, tokenId);
_profiles[tokenId] = Profile(name, age, profileImage);
profileToToken[msg.sender] = tokenId;
emit ProfileMinted(msg.sender, tokenId, name, age, profileImage);
}

Risk

Likelihood:

  • Any user can mint a profile with age 0 or 17 — this requires no exploit, just calling the function with a low value.

  • Automated bot registrations or tests commonly use age 0 or 1 as default values.

Impact:

  • Profiles with ages below 18 are permanently stored on-chain and encoded in immutable token URIs.

  • Protocol faces legal liability in jurisdictions requiring age verification for dating platforms (COPPA, GDPR, EU DSA).

  • Even if the frontend enforces age limits, the smart contract is the source of truth — direct contract interactions bypass any UI-layer checks.

Proof of Concept

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "forge-std/Test.sol";
import "../src/SoulboundProfileNFT.sol";
contract NoAgeValidationTest is Test {
SoulboundProfileNFT nft;
address alice = makeAddr("alice");
function setUp() public {
nft = new SoulboundProfileNFT();
}
function test_underage_profile_accepted() public {
// Age 0 is accepted — no revert
vm.prank(alice);
nft.mintProfile("Alice", 0, "ipfs://alice"); // @> should revert, does not
uint256 tokenId = nft.profileToToken(alice);
assertTrue(tokenId != 0, "Profile minted with age 0");
}
function test_age_17_accepted() public {
vm.prank(alice);
nft.mintProfile("Alice", 17, "ipfs://alice"); // @> should revert, does not
assertTrue(nft.profileToToken(alice) != 0);
}
function test_impossible_age_accepted() public {
vm.prank(alice);
nft.mintProfile("Alice", 255, "ipfs://alice"); // @> 255 years old accepted
assertTrue(nft.profileToToken(alice) != 0);
}
}

Recommended Mitigation

Add minimum and maximum age bounds to mintProfile():

// SoulboundProfileNFT.sol
uint8 public constant MIN_AGE = 18;
uint8 public constant MAX_AGE = 120;
function mintProfile(
string memory name,
uint8 age,
string memory profileImage
) external {
require(profileToToken[msg.sender] == 0, "Profile already exists");
// @> enforce age bounds
require(age >= MIN_AGE, "Must be at least 18 years old");
require(age <= MAX_AGE, "Invalid age");
uint256 tokenId = ++_nextTokenId;
_safeMint(msg.sender, tokenId);
_profiles[tokenId] = Profile(name, age, profileImage);
profileToToken[msg.sender] = tokenId;
emit ProfileMinted(msg.sender, tokenId, name, age, profileImage);
}
Updates

Lead Judging Commences

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