First Flight #12: Kitty Connect

First Flight #12: Kitty Connect
Beginner FriendlyFoundryNFTGameFi
100 EXP
View results
Submission Details
Severity: high
Valid

Transferred cats id not removed from original owners `s_ownerToCatsTokenId`

Summary

When cats transferred through KittyConnect::safeTransferFrom using _updateOwnershipInfo they are not removed from the original owners s_ownerToCatsTokenId field in storage.

Vulnerability Details

After a cat is transferred, the id of that cat still remains attached to the original owner through the kittyConnect.getCatsTokenIdOwnedBy(user); function, so as a cat is transferred around it will leave its Id on anyone who owns it.

POC test

function test_bridgeTest() public {
string memory catImageIpfsHash = "ipfs://QmbxwGgBGrNdXPm84kqYskmcMT3jrzBN8LzQjixvkz4c62";
vm.startPrank(partnerA);
kittyConnect.mintCatToNewOwner(user, catImageIpfsHash, "Hehe", "Hehe", block.timestamp);
kittyConnect.mintCatToNewOwner(user, catImageIpfsHash, "Hehe2", "Hehe2", block.timestamp);
kittyConnect.mintCatToNewOwner(user, catImageIpfsHash, "Hehe3", "Hehe3", block.timestamp);
vm.stopPrank();
vm.startPrank(user);
// Recreate a user approving thier transfer to new cat owner, then partner safe xfers, but hte
// original owner will still ahve the id in their getCatTokensIdOwnedBy list
uint256 tokenId = 2;
address newOwner = makeAddr("newOwner");
kittyConnect.approve(newOwner, tokenId);
vm.stopPrank();
vm.startPrank(partnerA);
kittyConnect.safeTransferFrom(user, newOwner, tokenId);
vm.stopPrank();
vm.startPrank(user);
assertEq(kittyConnect.getCatsTokenIdOwnedBy(user).length, 3); // [0, 1, 2]
assertEq(kittyConnect.getCatsTokenIdOwnedBy(newOwner).length, 1); // [2]
assert(kittyConnect.ownerOf(tokenId) == newOwner);
uint256[] memory usercats = kittyConnect.getCatsTokenIdOwnedBy(user);
assert(usercats[2] == tokenId); // Original owner still owns id 2 according to this variable
}

Impact

If another blockchain application is to look at this as confirmation of ownership it could cause problems, and confusion for users tracking their owned catIds

Tools Used

Manual Review, Solidity testing

Recommendations

Remove the id from s_ownerToCatsTokenId when transferring cats between users in _updateOwnershipInfo like we do when bridging our cats.

function _updateOwnershipInfo(address currCatOwner, address newOwner, uint256 tokenId) internal {
s_catInfo[tokenId].prevOwner.push(currCatOwner);
s_catInfo[tokenId].idx = s_ownerToCatsTokenId[newOwner].length;
s_ownerToCatsTokenId[newOwner].push(tokenId);
+ // Remove the token id from the previous owner's list
+ uint256[] memory userTokenIds = s_ownerToCatsTokenId[currCatOwner];
+ uint256 lastItem = userTokenIds[userTokenIds.length - 1];
+ s_ownerToCatsTokenId[currCatOwner].pop();
+ uint256 idx = s_catInfo[tokenId].idx;
+ if (idx < (userTokenIds.length - 1)) {
+ s_ownerToCatsTokenId[currCatOwner][idx] = lastItem;
+ }
}
Updates

Lead Judging Commences

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

Improper token ownership update in `_updateOwnershipInfo`

Support

FAQs

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