DatingDapp

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

Low: Approvals Remain Enabled Despite Soulbound Transfer Restrictions

Low: Approvals Remain Enabled Despite Soulbound Transfer Restrictions

Description

  • The protocol intends profile NFTs to be soulbound and permanently non-transferable.

  • Although transfer functions revert, approval-related functions inherited from ERC721 remain enabled.

  • Users may still call approve() and setApprovalForAll() successfully even though approved operators cannot ultimately transfer tokens.

  • This creates misleading protocol behavior and inconsistent UX for users and integrators.

// Root cause in the codebase with @> marks to highlight the relevant section
// @> Transfer functions blocked
function transferFrom(address, address, uint256) public pure override {
revert SoulboundTokenCannotBeTransferred();
}
// @> Approval functions remain inherited from ERC721
// function approve(address to, uint256 tokenId)
// function setApprovalForAll(address operator, bool approved)

Risk

Likelihood:

  • Wallets and NFT marketplaces commonly expose approval functionality to users.

  • Users may unintentionally approve operators assuming transfers are possible.

Impact:

  • Users may become confused about actual NFT transferability.

  • Integrators may incorrectly assume approved operators can move profile NFTs.

  • Protocol behavior becomes inconsistent with soulbound expectations.

Proof of Concept

The following test demonstrates that approvals can still be granted even though transfers always revert.

function testApprovalsStillAllowed() public {
vm.prank(user);
soulboundNFT.mintProfile("Alice", 25, "ipfs://profileImage");
uint256 tokenId = soulboundNFT.profileToToken(user);
vm.prank(user);
soulboundNFT.approve(user2, tokenId);
assertEq(
soulboundNFT.getApproved(tokenId),
user2
);
}

Recommended Mitigation

Disable approval-related functionality for soulbound tokens.

+ function approve(address, uint256) public pure override {
+ revert SoulboundTokenCannotBeTransferred();
+ }
+ function setApprovalForAll(address, bool) public pure override {
+ revert SoulboundTokenCannotBeTransferred();
+ }
Updates

Lead Judging Commences

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