Beginner FriendlyFoundryNFT
100 EXP
View results
Submission Details
Severity: low
Invalid

Missing validation in the `Soulmate.sol::readMessageInSharedSpace()` function allows the ones without soulmate to read messages in the shared space reserved for holders of the NFT with id `0`

Summary

Missing validation check in the Soulmate.sol::readMessageInSharedSpace() function will allow the ones without soulmate to read messages in the shared space reserved for holders of the NFT with id 0

Vulnerability Details

The Soulmate.sol::readMessageInSharedSpace() is implemented as follows:

function readMessageInSharedSpace() external view returns (string memory) {
// Add a little touch of romantism
return
string.concat(
sharedSpace[ownerToId[msg.sender]],
", ",
niceWords[block.timestamp % niceWords.length]
);
}

ownerToId[msg.sender] will return 0 if msg.sender does not have a soulmate, resulting in a reading message in the shared space for holders of NFT with ID 0.

Impact

Users without soulmates can read messages in the shared space of soulmates who hold NFT with id 0.

Proof of Concept (PoC)

Add the following test in SoulmateTest.t.sol:

function test_NFTNonHoldersCanReadMessagesInTheSharedSpaceReservedForHoldersOfTokenWithIdZero(address random) public {
vm.assume(random != address(soulmateContract) && random != address(loveToken) &&
random != address(stakingContract) && random != address(airdropContract) &&
random != address(airdropVault) && random != address(stakingVault) &&
random != address(soulmate1) && random != address(soulmate2)
);
_mintOneTokenForBothSoulmates(); // token minted for `soulmate1` and `soulmate2`
vm.prank(soulmate1);
soulmateContract.writeMessageInSharedSpace("Buy some eggs");
address random = makeAddr("random");
vm.prank(random);
string memory message = soulmateContract.readMessageInSharedSpace(); // any account that doesn't hold a Soulmate NFT can read the message in the shared space reserved for holders of the NFT with ID 0
string[4] memory possibleText = [
"Buy some eggs, sweetheart",
"Buy some eggs, darling",
"Buy some eggs, my dear",
"Buy some eggs, honey"
];
bool found;
for (uint i; i < possibleText.length; i++) {
if (compare(possibleText[i], message)) {
found = true;
break;
}
}
assertTrue(found);
}

Run a test with forge test --mt test_NFTNonHoldersCanReadMessagesInTheSharedSpaceReservedForHoldersOfTokenWithIdZero.

Tools Used

  • Manual review

  • Foundry

Recommendations

The transaction should be reverted if the user who doesn't have a soulmate tries to read a message in the shared space.

Recommended changes to the Soulmate.sol::mintSoulmateToken() function:

/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
error Soulmate__alreadyHaveASoulmate(address soulmate);
error Soulmate__SoulboundTokenCannotBeTransfered();
+error Soulmate__CannotReadMessageInSharedSpaceOfOtherSoulmates();
function readMessageInSharedSpace() external view returns (string memory) {
if (soulmateOf[msg.sender] == address(0)) {
revert Soulmate__CannotReadMessageInSharedSpaceOfOtherSoulmates();
}
// Add a little touch of romantism
return
string.concat(
sharedSpace[ownerToId[msg.sender]],
", ",
niceWords[block.timestamp % niceWords.length]
);
}

Add the following import and test in SoulmateTest.t.sol:

function test_readMessageInSharedSpaceRevertsCallerWhenDoesntHaveSoulmate(address random) public {
vm.assume(random != address(soulmateContract) && random != address(loveToken) &&
random != address(stakingContract) && random != address(airdropContract) &&
random != address(airdropVault) && random != address(stakingVault) &&
random != address(soulmate1) && random != address(soulmate2)
);
_mintOneTokenForBothSoulmates(); // token minted for `soulmate1` and `soulmate2`
vm.prank(soulmate1);
soulmateContract.writeMessageInSharedSpace("Buy some eggs");
address random = makeAddr("random");
vm.prank(random);
vm.expectRevert(Soulmate.Soulmate__CannotReadMessageInSharedSpaceOfOtherSoulmates.selector);
string memory message = soulmateContract.readMessageInSharedSpace(); // account that doesn't have a soulmate can't read messages in the shared space
}

Run a test with forge test --mt test_readMessageInSharedSpaceRevertsCallerWhenDoesntHaveSoulmate.

Updates

Lead Judging Commences

0xnevi Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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