Summary
The mintProfile
function accepts a uint8
for age without proper validation, allowing creation of profiles with ages 0-255, which could enable underage users and unrealistic age values.
Vulnerability Details
contract SoulboundProfileNFT is ERC721, Ownable {
struct Profile {
string name;
uint8 age;
string profileImage;
}
function mintProfile(
string memory name,
uint8 age,
string memory profileImage
) external {
require(profileToToken[msg.sender] == 0, "Profile already exists");
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);
}
}
POC
function testInvalidAgeProfiles() public {
vm.startPrank(address(0x1));
soulboundNFT.mintProfile("Teen", 13, "ipfs://profile1");
vm.stopPrank();
vm.startPrank(address(0x2));
soulboundNFT.mintProfile("Child", 0, "ipfs://profile2");
vm.stopPrank();
vm.startPrank(address(0x3));
soulboundNFT.mintProfile("Invalid", 255, "ipfs://profile3");
vm.stopPrank();
}
Impact
-
Underage users could create profiles
-
Platform could face legal issues
-
Minors could interact with adults
-
Potential for exploitation
Recommendations
contract SoulboundProfileNFT is ERC721, Ownable {
+ uint8 public constant MINIMUM_AGE = 18;
+ uint8 public constant MAXIMUM_AGE = 100;
+
+ error InvalidAge(uint8 age);
+ error UnderageProfile(uint8 age);
+ event AgeVerificationFailed(address indexed user, uint8 age);
struct Profile {
string name;
uint8 age; // uint8 ranges from 0-255
string profileImage;
}
function mintProfile(
string memory name,
uint8 age,
string memory profileImage
) external {
require(profileToToken[msg.sender] == 0, "Profile already exists");
+ // Age validation
+ if (age < MINIMUM_AGE) {
+ emit AgeVerificationFailed(msg.sender, age);
+ revert UnderageProfile(age);
+ }
+ if (age > MAXIMUM_AGE) {
+ revert InvalidAge(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);
}
}