New BAKC Owner Can Steal ApeCoin #284
Labels
2 (Med Risk)
Assets not at direct risk, but function/availability of the protocol could be impacted or leak value
bug
Something isn't working
downgraded by judge
Judge downgraded the risk level of this issue
M-06
primary issue
Highest quality submission among a set of duplicates
satisfactory
satisfies C4 submission criteria; eligible for awards
selected for report
This submission will be included/highlighted in the audit report
Lines of code
https://github.com/code-423n4/2022-11-paraspace/blob/c6820a279c64a299a783955749fdc977de8f0449/paraspace-core/contracts/protocol/tokenization/libraries/ApeStakingLogic.sol#L38
Vulnerability details
Background
This section provides a context of the pre-requisite concepts that a reader needs to fully understand the issue.
Split Pair Edge Case In Paired Pool
Assume that Jimmy is the owner of BAYC #8888 and BAKC #9999 NFTs initially. He participated in the Paired Pool and staked + accrued a total of 100 ApeCoin (APE) at this point, as shown in the diagram below.
Jimmy then sold his BAKC #9999 NFT to Ben. When this happens, both parties (Jimmy and Ben) could close out their staking position. Since Ben owns BAKC #9999 now, he can close out Jimmy's position anytime and claim all the accrued APE rewards (2 APE below). While Jimmy will obtain the 98 APE that he staked initially.
The following image is taken from https://youtu.be/_LO-1f9nyjs?t=640
The
ApeCoinStaking._withdrawPairNft
taken from the official $APE Staking Contract shows that the implementation allows both the BAYC/MAYC owners and BAKC owners to close out the staking position. Refer to Line 976 below.When the staking position is closed by the BAKC owners, the entire staking amount must be withdrawn. A partial amount is not allowed per Line 981 below. In Line 984, all the accrued APE rewards will be sent to the BAKC owners. In Line 989, all the staked APEs will be withdrawn (unstake) and sent directly to the wallet of the BAYC owners.
https://github.com/code-423n4/2022-11-paraspace/blob/c6820a279c64a299a783955749fdc977de8f0449/paraspace-core/contracts/dependencies/yoga-labs/ApeCoinStaking.sol#L966
The following shows that the
ApeCoinStaking._withdraw
used in the above function will send the unstaked APEs directly to the wallet of BAYC owners. Refer to Line 946 below.https://github.com/code-423n4/2022-11-paraspace/blob/c6820a279c64a299a783955749fdc977de8f0449/paraspace-core/contracts/dependencies/yoga-labs/ApeCoinStaking.sol#L937
Who is the owner of BAYC/MAYC in ParaSpace?
The BAYC is held by the
NTokenBAYC
reserve pool, while the MAYC is held byNTokenMAYC
reserve pool. This causes an issue because, as mentioned in the previous section, all the unstaked APE will be sent directly to the wallet of the BAYC/MAYC owners. This will be used as part of the attack path later on.Does BAKC need to be staked or stored within ParaSpace?
No. For the purpose of APE staking via ParaSpace , BAKC NFT need not be held in the ParaSpace contract for staking, but Bored Apes and Mutant Apes must be collateralized in the ParaSpace protocol. Refer to here. As such, users are free to sell off their BAKC anytime to anyone since it is not being locked up.
Proof of Concept
Using back the same example in the previous section. Assume the following:
Ben will close out Jimmy's position by calling the
ApeCoinStaking.withdrawBAKC
function of the official $APE Staking Contract to withdraw all the staked APE + accrued APE rewards. As a result, the 98 APE that Jimmy staked initially will be sent directly to the owner of the BAYC #8888 owner. In this case, the BAYC #8888 owner is ParaSpace'sNTokenBAYC
reserve pool.At this point, it is important to note that Jimmy's 98 APE is stuck in ParaSpace's
NTokenBAYC
reserve pool. If anyone can siphon out Jimmy's 98 APE that is stuck in the contract, that person will be able to get free APE.There exist a way to siphon out all the APE coin that resides in ParaSpace's
NTokenBAYC
reserve pool. Anyone who participates in APE staking via ParaSpace with a BAYC, which also means that any user staked in the Paired Pool, can trigger theApeStakingLogic.withdrawBAKC
function below by calling thePoolApeStaking.withdrawBAKC
function.Notice that in Line 53 below, it will compute the total balance of APE held by ParaSpace's
NTokenBAYC
reserve pool contract. In Line 55, it will send all the APE in the pool contract to the recipient. This effectively performs a sweeping of APE stored in the pool contract.https://github.com/code-423n4/2022-11-paraspace/blob/c6820a279c64a299a783955749fdc977de8f0449/paraspace-core/contracts/protocol/tokenization/libraries/ApeStakingLogic.sol#L38
Thus, after Ben closes out Jimmy's position by calling the
ApeCoinStaking.withdrawBAKC
function and causes the 98 APE to be sent to ParaSpace'sNTokenBAYC
reserve pool contract, Ben immediately calls thePoolApeStaking.withdrawBAKC
function against his own BAYC #2 and BAKC #2 NFTs. This will result in all of Jimmy's 98 APE being swept to his wallet. Bob effectively steals Jimmy's 98 APE.Impact
ApeCoin of ParaSpace users can be stolen.
Recommended Mitigation Steps
Consider the potential side effects of the split pair edge case in the pair pool when implementing the APE staking feature in ParaSpace.
The official APE staking contract has been implemented recently, and only a few protocols have integrated with it. Thus, the edge cases are not widely understood and are prone to errors.
To mitigate this issue, instead of returning BAKC NFT to the users after staking, consider locking up BAKC NFT in the ParaSpace contract as part of the user's collateral. In this case, the user will not be able to sell off their BAKC, and the "Split Pair Edge Case In Paired Pool" scenario will not happen.
The text was updated successfully, but these errors were encountered: