mintProfile performs the external ERC721 receiver callback in _safeMint before setting profileToToken[msg.sender]. A malicious receiver can re-enter mintProfile from onERC721Received; every nested call still observes a zero mapping and mints another soulbound NFT.
The uniqueness check is at src/SoulboundProfileNFT.sol:31. The external interaction occurs at line 34, but the state that enforces uniqueness is not written until line 38. This violates checks-effects-interactions.
During the callback, the attacker recursively calls mintProfile. Multiple token IDs are minted to the same address. Only the last returned call's token ID remains in profileToToken, leaving the other soulbound tokens owned by the attacker but not addressable through the profile mapping and impossible to transfer.
An attacker bypasses the protocol's core one-profile-per-address guarantee and can create inconsistent, orphaned profile NFTs.
Set profileToToken[msg.sender] = tokenId before _safeMint (and store metadata before the callback if callbacks must observe a complete profile). A revert from _safeMint will revert those writes. A nonReentrant guard is an acceptable secondary defense.
Use an ERC721Receiver whose callback attempts a second mintProfile. Assert that the nested call reverts with Profile already exists, only one token is minted, and the mapping points to it.
The contest is live. Earn rewards by submitting a finding.
Submissions are being reviewed by our AI judge. Results will be available in a few minutes.
View all submissionsThe contest is complete and the rewards are being distributed.