DatingDapp

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

LikeRegistry does not validate _profileNFT at deployment

Root + Impact

Description

  • The LikeRegistry constructor accepts a _profileNFT address parameter and wraps it directly into a SoulboundProfileNFT interface, which is then used by likeUser() to validate that both the liker and liked user hold a profile NFT before recording a like.

No zero-address check or interface validation is performed at construction time — any address, including address(0) or a completely unrelated contract, is silently accepted. The failure only surfaces at runtime when likeUser() calls profileToToken(), permanently bricking the protocol with no recovery path short of full redeployment.

// Root cause in the codebase with @> marks to highlight the relevant section

Risk

Likelihood:

  • Low. Only triggered by deployer error — wrong address copy-paste, deploying to a new chain without redeploying the NFT contract first, or a botched migration/upgrade script.

Impact:

  • Medium. If _profileNFT is set to the zero address or a non-SoulboundProfileNFT contract, every likeUser() call reverts permanently. The entire protocol is bricked at deployment with no upgrade path — requires full redeployment.


Proof of Concept

The constructor blindly wraps whatever address it receives into a SoulboundProfileNFT interface. No zero-address check, no interface validation. A bad address silently passes construction and only fails at runtime when profileToToken() is called.

Create a new test contract in new test folder

Ran with command: forge test --match-path InvalidProfileNFTPoC.t.sol -vvvv

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "forge-std/Test.sol";
import "../src/LikeRegistry.sol";
import "../src/SoulboundProfileNFT.sol";
contract InvalidProfileNFTPoC is Test {
address alice = address(0xA11CE);
address bob = address(0xB0B);
function setUp() public {
vm.deal(alice, 1 ether);
vm.deal(bob, 1 ether);
}
function testDeployWithZeroAddress() public {
// Constructor accepts zero address with no complaint
LikeRegistry likeRegistry = new LikeRegistry(address(0));
// Protocol is silently bricked — likeUser() reverts for every caller
vm.prank(alice);
vm.expectRevert();
likeRegistry.likeUser{value: 1 ether}(bob);
}
function testDeployWithWrongContract() public {
// Deploy an unrelated contract and pass it as the NFT address
address randomContract = address(new SomeOtherContract());
LikeRegistry likeRegistry = new LikeRegistry(randomContract);
// profileToToken() call hits a contract that doesn't implement it
// — reverts with no useful error message
vm.prank(alice);
vm.expectRevert();
likeRegistry.likeUser{value: 1 ether}(bob);
}
}
contract SomeOtherContract {}

Recommended Mitigation

Validate the address and do a minimal interface sanity-check in the constructor.

constructor(address _profileNFT) Ownable(msg.sender) {
require(_profileNFT != address(0), "Invalid NFT contract address");
// Sanity-check: ensure the address actually responds to profileToToken()
// A call to a non-contract or wrong contract will revert here at deploy
// time rather than silently at runtime.
try SoulboundProfileNFT(_profileNFT).profileToToken(address(0)) {
} catch {
// Expected to return 0 for unknown address — any revert here means
// the contract does not implement the expected interface
revert("Address does not implement SoulboundProfileNFT");
}
profileNFT = SoulboundProfileNFT(_profileNFT);
}
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!