DatingDapp

First Flight #33
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Severity: medium
Valid

Blocked users can create new profiles, making the blocking feature ineffective

M-1 Blocked users can create new profiles, making the blocking feature ineffective

Description
The blockProfile() function in SoulboundProfileNFT.sol is intended to allow the contract owner to block malicious users. However, blocked users can simply create a new profile after being blocked, making the blocking mechanism ineffective.

This was demonstrated in the test test_user_blocked_can_come_back_and_create_new_account() where a blocked user successfully creates a new profile.

Impact

  1. This undermines the platform's ability to remove bad actors and protect users

  2. Could lead to repeated harassment or abuse if malicious users keep creating new profiles

  3. Wastes gas and effort of admins who try to block users

  4. Reduces trust in the platform's safety mechanisms

Proof of Concept:

function test_user_blocked_can_come_back_and_create_new_account() public {
// Arrange
_mintSoulNFT(USER1, "User 1", 20, "https://example.com/image.png");
console2.log("user1 soulboundProfileNFT balance", soulboundProfileNFT.balanceOf(USER1));
// Act
soulboundProfileNFT.blockProfile(USER1); //user have been blocked
console2.log("user1 soulboundProfileNFT balance", soulboundProfileNFT.balanceOf(USER1));
// Assert
vm.startPrank(USER1);
soulboundProfileNFT.mintProfile("User 1", 20, "https://example.com/image.png");
vm.stopPrank();
console2.log("user1 soulboundProfileNFT balance", soulboundProfileNFT.balanceOf(USER1));
assertEq(soulboundProfileNFT.balanceOf(USER1), 1);
}

Logs

[PASS] test_user_blocked_can_come_back_and_create_new_account() (gas: 265728)
Logs:
user1 soulboundProfileNFT balance 1
user1 soulboundProfileNFT balance 0
user1 soulboundProfileNFT balance 1

Recommended Mitigation:

To effectively prevent blocked users from creating new profiles, we need to implement persistent address blocking with proper access controls and events.

// State variables
+ /// @notice Mapping to track permanently blocked addresses
+ /// @dev Once an address is blocked, it can never create new profiles
+ mapping(address => bool) public blockedAddresses;
+ /// @notice Emitted when an address is blocked
+ /// @param blockedAddress The address that was blocked
+ /// @param reason The reason for blocking
+ event AddressBlocked(address indexed blockedAddress, string reason);
+ /// @notice Modifier to prevent blocked addresses from interacting
+ /// @param user The address to check
+ modifier notBlocked(address user) {
+ require(!blockedAddresses[user], "Address blocked from platform");
+ _;
+ }
function blockProfile(address blockAddress) external onlyOwner {
uint256 tokenId = profileToToken[blockAddress];
require(tokenId != 0, "Profile does not exist");
+ // Mark address as blocked before burning profile
+ blockedAddresses[blockAddress] = true;
// Burn their profile
_burn(tokenId);
delete profileToToken[blockAddress];
delete _profiles[tokenId];
+ // Emit both events
emit ProfileBurned(blockAddress, tokenId);
+ emit AddressBlocked(blockAddress, "Profile blocked by admin");
}
- function mintProfile(string memory name, uint8 age, string memory profileImage) external {
+ /// @notice Creates a new profile NFT
+ /// @dev Reverts if sender is blocked or already has a profile
+ function mintProfile(string memory name, uint8 age, string memory profileImage)
+ external notBlocked(msg.sender)
{
require(profileToToken[msg.sender] == 0, "Profile already exists");
// ... rest of existing function
}
- function burnProfile() external {
+ function burnProfile() external notBlocked(msg.sender) {
uint256 tokenId = profileToToken[msg.sender];
require(tokenId != 0, "No profile to burn");
_burn(tokenId);
delete profileToToken[msg.sender];
delete _profiles[tokenId];
emit ProfileBurned(msg.sender, tokenId);
}
+ /// @notice Checks if an address is blocked
+ /// @param user Address to check
+ /// @return bool True if address is blocked
+ function isBlocked(address user) external view returns (bool) {
+ return blockedAddresses[user];
+ }

This improved implementation:

  1. Adds proper NatSpec documentation for all new functions and state variables

  2. Introduces an event to track blocking actions with reasons

The blocking mechanism is now:

  • Persistent (blocked addresses can't create new profiles)

  • Transparent (emits events with reasons)

  • Well-documented

  • Gas-efficient (uses single storage reads)

  • Properly access-controlled

Updates

Appeal created

n0kto Lead Judge 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

finding_blocked_user_can_recreate_a_profil

Likelihood: Low, any blocked users. Impact: High, not really blocked.

Support

FAQs

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