Beginner FriendlyFoundryNFT
100 EXP
View results
Submission Details
Severity: medium
Valid

Anybody who don't have nft (neither a soulmate) can create misunderstandings in first couple due to flaw in Write and read message logic

Summary

first couple, which has nft id 0, there msg can be overridden by other users, which don't have shared nft.

Vulnerability Details

Soulmate contract has two function to communicate with partners. Given below -

/// @notice Allows any soulmates with the same NFT ID to write in a shared space on blockchain.
/// @param message The message to write in the shared space.
function writeMessageInSharedSpace(string calldata message) external {
@> uint256 id = ownerToId[msg.sender];
sharedSpace[id] = message;
emit MessageWrittenInSharedSpace(id, message);
}
/// @notice Allows any soulmates with the same NFT ID to read in a shared space on blockchain.
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]
);
}

It works as intended for most cases, except for one case. If you check the highlighted line, it check the ownerToId , which keep tracks of valid users which are in a relationship.

But it fails due to default value of mapping which is 0, so when someone who don't have nft, can write msg to use who actually shares Nft id 0. This is not a good thing and must be avoided at all cost.

Due to miscommunication / misunderstandings, couple could lead to divorce.

POC

create testThirdpartyCanCreateMisunderstandingInFirstCouple in existing SoulmateTest.t.sol file

function testThirdpartyCanCreateMisunderstandingInFirstCouple() public {
// we already have soulmate 1 and soulmate 2
// in existing code
// so just create 2 more third party users for our test
address romeo = makeAddr("Romeo");
address romeoFriend = makeAddr("RomeoFriend");
_mintOneTokenForBothSoulmates();
/// let's test msg write function
/// real lover asking her guy to buy some eggs
vm.prank(soulmate1);
soulmateContract.writeMessageInSharedSpace("Buy some eggs");
/// Before soulmate 2, could read
/// romeo quickly update the message
vm.prank(romeo);
soulmateContract.writeMessageInSharedSpace("Buy some Apples");
/// let's read msg by soulmate 2
vm.prank(soulmate2);
string memory message1 = soulmateContract.readMessageInSharedSpace();
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], message1)) {
found = true;
break;
}
}
if(!found){console2.log("expected msg not found");}
console2.log("soulmate2 received:", message1);
/// This process is applicable to vice versa
/// when soulmate 2 send msg to soulmate 1
vm.prank(soulmate2);
soulmateContract.writeMessageInSharedSpace("okay");
/// before soulmate 1 can see okay,
/// romeo friend update the msg
vm.prank(romeoFriend);
soulmateContract.writeMessageInSharedSpace("I don't have time do all this. Do it yourself");
/// soulmate 1 will be see above msg
vm.prank(soulmate1);
string memory message2 = soulmateContract.readMessageInSharedSpace();
string[4] memory possibleText2 = [
"Buy some eggs, sweetheart",
"Buy some eggs, darling",
"Buy some eggs, my dear",
"Buy some eggs, honey"
];
bool found2;
for (uint i; i < possibleText2.length; i++) {
if (compare(possibleText2[i], message2)) {
found2 = true;
break;
}
}
if(!found2){console2.log("expected msg not found");}
console2.log("soulmate1 received:", message2);
}

run the following command in terminal forge test --mt testThirdpartyCanCreateMisunderstandingInFirstCouple -vv , it will show following output.

[⠢] Compiling...
[⠒] Compiling 1 files with 0.8.23
[⠢] Solc 0.8.23 finished in 1.96s
Running 1 test for test/unit/SoulmateTest.t.sol:SoulmateTest
[PASS] testThirdpartyCanCreateMisunderstandingInFirstCouple() (gas: 318185)
Logs:
expected msg not found
soulmate2 received: Buy some Apples, darling
expected msg not found
soulmate1 received: I don't have time do all this. Do it yourself, darling
Test result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.19ms
Ran 1 test suites: 1 tests passed, 0 failed, 0 skipped (1 total tests)

Impact

Misunderstanding due to miscommunication will leads to divorce of a happy couple.

Tools Used

Manual Review

Recommendations

Here is simple fix for it -
start token id from 1 in contract.

- uint256 private nextID;
+ uint256 private nextID = 1;
Updates

Lead Judging Commences

0xnevi Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

finding-write-message-nft-0-id

Medium Severity, This has an indirect impact and influence on the possibility of divorce between soulmates owning the first soulmate NFT id0, leading to permanent loss of ability to earn airdrops/staking rewards.

Support

FAQs

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