Santa's List

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

`blockProfile()` trivially bypassed -- blocked users can immediately re-mint

Description

  • The owner is expected to be able to permanently block malicious users by calling blockProfile(), which burns their NFT and removes their profile.

  • blockProfile() deletes profileToToken[user], setting it to 0. However, mintProfile() checks require(profileToToken[msg.sender] == 0) -- the exact post-deletion state. A blocked user can call mintProfile() immediately to re-enter the system, completely nullifying the admin action.

function blockProfile(address blockAddress) external onlyOwner {
uint256 tokenId = profileToToken[blockAddress];
require(tokenId != 0, "No profile found");
_burn(tokenId);
delete profileToToken[blockAddress]; // @> sets to 0
delete _profiles[tokenId];
emit ProfileBurned(blockAddress, tokenId);
}
function mintProfile(string memory name, uint8 age, string memory profileImage) external {
require(profileToToken[msg.sender] == 0, "Profile already exists"); // @> 0 == 0 passes for blocked users
// ...
}

Risk

Likelihood:

  • This occurs every time the owner attempts to block a user -- the blocked user can re-register in the very next block

  • No additional conditions or costs are required beyond the gas fee for calling mintProfile()

Impact:

  • The admin blocking mechanism is completely non-functional -- blocked users can immediately rejoin

  • Malicious users cannot be permanently removed from the protocol

Proof of Concept

function testBlockProfileBypass() public {
// Malicious user mints profile
vm.prank(malicious);
profileNFT.mintProfile("Bad Actor", 30, "img");
// Owner blocks the user
vm.prank(owner);
profileNFT.blockProfile(malicious);
// Blocked user immediately re-mints -- bypass complete
vm.prank(malicious);
profileNFT.mintProfile("New Identity", 25, "newimg");
// User is fully active again
assertNotEq(profileNFT.profileToToken(malicious), 0);
}

Recommended Mitigation

+ mapping(address => bool) public blocked;
function blockProfile(address blockAddress) external onlyOwner {
uint256 tokenId = profileToToken[blockAddress];
require(tokenId != 0, "No profile found");
+ blocked[blockAddress] = true;
_burn(tokenId);
delete profileToToken[blockAddress];
delete _profiles[tokenId];
emit ProfileBurned(blockAddress, tokenId);
}
function mintProfile(string memory name, uint8 age, string memory profileImage) external {
require(profileToToken[msg.sender] == 0, "Profile already exists");
+ require(!blocked[msg.sender], "Address is blocked");
// ...
}
Updates

Lead Judging Commences

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