DatingDapp

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

Incorrect Operation Order in SoulboundProfileNFT's burnProfile Function

Summary

The burnProfile function in SoulboundProfileNFT performs an external interaction (_burn) before state modifications, which doesn't follow the Checks-Effects-Interactions pattern.

Vulnerability Details

In SoulboundProfileNFT.sol, the burnProfile function:

  1. Calls _burn (external interaction) first

  2. Then modifies state variables with delete operations

  3. Does not follow the CEI pattern

function burnProfile() external {
uint256 tokenId = profileToToken[msg.sender];
require(tokenId != 0, "No profile found");
require(ownerOf(tokenId) == msg.sender, "Not profile owner");
_burn(tokenId); // External interaction first
delete profileToToken[msg.sender]; // State modification after
delete _profiles[tokenId]; // State modification after
emit ProfileBurned(msg.sender, tokenId);
}

Impact

  1. Pattern Violation : Does not follow the Checks-Effects-Interactions pattern

  2. Future Risk : Could be vulnerable if _burn is modified to include callbacks

  3. Maintainability : Makes the code more prone to vulnerabilities during updates

Severity: LOW - Currently safe as _burn doesn't include callbacks, but could be risky in future updates

Tools Used

  • Manual code review

  • Best practices analysis

Recommendations

  1. Reorder operations to follow CEI pattern:

function burnProfile() external {
uint256 tokenId = profileToToken[msg.sender];
require(tokenId != 0, "No profile found");
require(ownerOf(tokenId) == msg.sender, "Not profile owner");
// 1. State modifications first
delete profileToToken[msg.sender];
delete _profiles[tokenId];
// 2. External interaction last
_burn(tokenId);
emit ProfileBurned(msg.sender, tokenId);
}
  1. Add reentrancy protection:

import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract SoulboundProfileNFT is ERC721, ReentrancyGuard {
function burnProfile() external nonReentrant {
// ... rest of the code ...
}
}
  1. Consider implementing a two-step burn process:

mapping(address => bool) public burnPending;
uint256 public constant BURN_DELAY = 1 days;
mapping(address => uint256) public burnRequestTime;
function requestBurn() external {
uint256 tokenId = profileToToken[msg.sender];
require(tokenId != 0, "No profile found");
require(ownerOf(tokenId) == msg.sender, "Not profile owner");
burnPending[msg.sender] = true;
burnRequestTime[msg.sender] = block.timestamp;
emit BurnRequested(msg.sender, tokenId);
}
function executeBurn() external {
require(burnPending[msg.sender], "No burn requested");
require(block.timestamp >= burnRequestTime[msg.sender] + BURN_DELAY, "Burn delay not elapsed");
uint256 tokenId = profileToToken[msg.sender];
delete burnPending[msg.sender];
delete burnRequestTime[msg.sender];
delete profileToToken[msg.sender];
delete _profiles[tokenId];
_burn(tokenId);
emit ProfileBurned(msg.sender, tokenId);
}
Updates

Appeal created

n0kto Lead Judge 5 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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