Releasing an NFT by the liquidator does not update the mapping idToUnderlying
and does not burn the collateralId
#196
Labels
3 (High Risk)
Assets can be stolen/lost/compromised directly
bug
Something isn't working
duplicate-480
edited-by-warden
judge review requested
Judge should review this issue
satisfactory
satisfies C4 submission criteria; eligible for awards
sponsor confirmed
Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity")
Lines of code
https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/CollateralToken.sol#L331
Vulnerability details
Impact
The
ClearingHouse
is supposed to be the owner of the collateralized NFT always. The only time that it is not the owner, is duringflashAction
in which the NFT will be transferred back to theClearingHouse
at the end of the transaction. The ownership is tracked byownerOf(collateralId)
, and the NFT data is tracked bys.idToUnderlying[collateralId]
. In a normal case, if an NFT is going to be released by calling the functionreleaseToAddress
, these data will be burned and removed,ownerOf(collateralId) = address(0)
anddelete s.idToUnderlying[collateralId]
.https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/CollateralToken.sol#L331
But, this is not the case if the NFT is going to be released by a liquidator during an auction.
Proof of Concept
CollateralToken.sol
to be used as collateral. This transfer triggers theonERC721Received
:https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/CollateralToken.sol#L553
collateralId
to this NFT by appending the token contract address and token id.https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/CollateralToken.sol#L560
ClearingHouse
contract and transfers this NFT to that contract.https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/CollateralToken.sol#L578
https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/CollateralToken.sol#L588
So, we will have:
ERC721(tokenContract).ownerOf(tokenId) = the address of the deployed contract ClearingHouse
s.clearingHouse[collateralId] = the address of the deployed contract ClearingHouse
ownerOf(collateralId) = Alice
s.idToUnderlying[collateralId].tokenContract = address of the token contract
Suppose later, Alice is going to be liquidated, and her collateral (her NFT which is locked in the ClearingHouse) is auctioned.
After the liquidation, the liquidator should claim this NFT by calling
liquidatorNFTClaim
.https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/CollateralToken.sol#L109
_releaseToAddress
.https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/CollateralToken.sol#L352
In this function, the NFT will be transferred to the liquidator. So, we will have:
ERC721(tokenContract).ownerOf(tokenId) = the address of liquidator
s.clearingHouse[collateralId] = the address of the deployed contract ClearingHouse
ownerOf(collateralId) = Alice
s.idToUnderlying[collateralId].tokenContract = address of the token contract
This is the vulnerability, because that NFT is transferred to the liquidator, but the mapping
idToUnderlying
is not deleted and the mintedcollaterId
is not burned. In other words, it is correct to have the following states:ERC721(tokenContract).ownerOf(tokenId) = the address of liquidator
s.clearingHouse[collateralId] = the address of the deployed contract ClearingHouse
ownerOf(collateralId) = address(0)
s.idToUnderlying[collateralId].tokenContract = address(0)
This can lead to some issues. For example, if the liquidator sells this NFT to another innocent user (Bob):
CollateralToken
, it will be failed. Becauses.idToUnderlying[collateralId].tokenContract
is nonzero, and it means that this NFT has already used.https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/CollateralToken.sol#L598
ClearingHouse
already deployed for this NFT, he will loss this NFT, and can not take it back. Because, we have stillownerOf(collateralId) = Alice
, so only Alice will be able to release this NFT from the ClearingHouse.https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/CollateralToken.sol#L338
The situation can be even worse:
commitToLien
.https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/VaultImplementation.sol#L287
CT.ownerOf(collateralId)
is still Alice not address(0). Although, Alice's NFT was sold to the liquidator in the auction, butcollateralId
is not burned, so Alice is still owner of thiscollateralId
.commitToLien
>>_requestLienAndIssuePayout
>>_validateCommitment
https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/VaultImplementation.sol#L235
In summary, the issue is that the mapping and burning are done only in the function
releaseToAddress
, while the internal function_releaseToAddress
is called during claiming the NFT by the liquidator in the functionliquidatorNFTClaim
.Tools Used
Recommended Mitigation Steps
The following modifications should be applied:
The text was updated successfully, but these errors were encountered: