-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
transferShortRecord: Can transfer a newly created ShortRecord using a previously minted NFT #174
Comments
raymondfam marked the issue as insufficient quality report |
raymondfam marked the issue as primary issue |
Closely similar to Codehawks' H-05: https://www.codehawks.com/report/clm871gl00001mp081mzjdlwc#H-05. I think this issue has been fixed by the protocol. |
It seems valid and I will confirm with the sponsor during PJQA. |
hansfriese marked the issue as satisfactory |
hansfriese marked the issue as selected for report |
ditto-eth (sponsor) confirmed |
ditto-eth marked the issue as disagree with severity |
This scenario is technically possible, but only happens because of user error. I recommend low because a series of mistakes on the user's part would have to occur for this scenario:
|
This can be problematic not only in attacks, but also in general situations. For example, a user can approve to NFT marketplace contract in order to sell their NFT. A scenario is possible where a user approves an NFT for sale -> the SR is closed -> a new SR is created with the same ID -> and the NFT is sold. A user will think that it doesn't matter if the old NFT is sold because the closed SR will move. A user doesn't realize that the new SR will move when the old NFT is sold.
NFT should be minted independently per SR and should not affect each other. The current implementation implicitly points to multiple SRs with a single NFT. In a strict implementation, the past NFT should point to a closed SR, but due to optimizations, it doesn't. Revoking the approval of past SR NFTs to prevent the current SR from moving is not the right solution because it's violate the individuality of NFT and SR, and user would not think that they should revoke past approval to prevent to moving new SR. |
Thanks for your detailed comments. |
hansfriese changed the severity to 2 (Med Risk) |
Lines of code
https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/libraries/LibSRUtil.sol#L129-L131
Vulnerability details
Impact
Can move the newly created ShortRecord using the NFT that was minted in the past.
Proof of Concept
Even if the ShortRecord is closed, the previously minted NFT is not burnt. The
s.nftMapping[tokenId].shortRecordId
data is not deleted either. Therefore, when a ShortRecord is created by reusing the same ID, the existing NFT points to the new ShortRecord.However, when transferring the NFT and the ShortRecord, it does not check whether this NFT is a newly minted NFT or a past NFT. Those who have been allowed to transfer the NFT in the past still can transfer the newly created ShortRecord.
This is PoC. Add it to ERC721Facet.t.sol and run it.
Tools Used
Manual Review
Recommended Mitigation Steps
function transferShortRecord(address from, address to, uint40 tokenId) internal { AppStorage storage s = appStorage(); STypes.NFT storage nft = s.nftMapping[tokenId]; address asset = s.assetMapping[nft.assetId]; STypes.ShortRecord storage short = s.shortRecords[asset][from][nft.shortRecordId]; if (short.status == SR.Closed) revert Errors.OriginalShortRecordCancelled(); if (short.ercDebt == 0) revert Errors.OriginalShortRecordRedeemed(); + if (short.tokenId != tokenId) revert Errors.NotValidNFT(); // @dev shortOrderId is already validated in mintNFT if (short.status == SR.PartialFill) { LibOrders.cancelShort(asset, nft.shortOrderId); } short.tokenId = 0; LibShortRecord.deleteShortRecord(asset, from, nft.shortRecordId); LibBridgeRouter.transferBridgeCredit(asset, from, to, short.collateral); uint8 id = LibShortRecord.createShortRecord( asset, to, SR.FullyFilled, short.collateral, short.ercDebt, short.ercDebtRate, short.dethYieldRate, tokenId ); nft.owner = to; nft.shortRecordId = id; nft.shortOrderId = 0; }
Assessed type
Invalid Validation
The text was updated successfully, but these errors were encountered: