Platform: Code4rena
Start Date: 12/04/2023
Pot Size: $60,500 USDC
Total HM: 21
Participants: 199
Period: 7 days
Judge: hansfriese
Total Solo HM: 5
Id: 231
League: ETH
Rank: 21/199
Findings: 3
Award: $414.80
🌟 Selected for report: 1
🚀 Solo Findings: 0
🌟 Selected for report: carrotsmuggler
Also found by: Ace-30, KIntern_NA, Nyx, bin2chen, cccz, juancito, mahdikarimi, mov, nobody2018
261.4589 USDC - $261.46
Challenges, once created, cannot be closed. Thus once a challenge is created, the challenger has already transferred in a collateral amount and is thus open for losing their collateral to a bidding war which will most likely close below market price, since otherwise buying from the market would be cheaper for bidders.
Position owners can take advantage of this fact and frontrun a launchChallenge
transaction with an adjustPrice
transaction. The adjustPrice
function lets the user lower the price of the position, and can pass the collateral check by sending collateral tokens externally.
As a worst case scenario, consider a case where a position is open with 1 ETH collateral and 1500 ZCHF minted. A challenger challenges the position and the owner frontruns the challenger by sending the contract 1500 ZCHF and calling repay()
and then calling adjustPrice
with value 0, all in one transaction with a contract. Now, the price in the contract is set to 0, and the collateral check passes since the outstanding minted amount is 0. The challenger's transaction gets included next, and they are now bidding away their collateral, since any amount of bid will pass the avert collateral check.
The position owner themselves can backrun the same transaction with a bid of 1 wei and take all the challenger's collateral, since every bid checks for the tryAvertChallenge
condition.
if (_bidAmountZCHF * ONE_DEC18 >= price * _collateralAmount)
Since price is set to 0, any bid passes this check. This sandwich attack causes immense losses to all challengers in the system, baiting them with bad positions and then sandwiching their challenges.
Since sandwich attacks are extremely commonplace, this is classified as high severity.
The attack can be performed the following steps.
adjustPrice
call lowering the price.Manual Review
When launching a challenge, ask for a expectedPrice
argument. If the actual price does not match this expected price, that means that transaction was frontrun and should be reverted. This acts like a slippage check for challenges.
#0 - c4-pre-sort
2023-04-21T11:56:39Z
0xA5DF marked the issue as primary issue
#1 - 0xA5DF
2023-04-21T15:15:34Z
I have some doubts about severity, since the auction's final bid is expected to be at about the worth of the collateral. So the challenger isn't expected to lose anything but the challenge reward.
#2 - luziusmeisser
2023-04-29T23:15:48Z
This is actually a high risk issue as the challenge is ended early as soon as the highest bid reaches the liquidation price.
I would even say that this is one of the most valuable findings I've seen so far!
The fix is to add front-running protection to the launchChallenge function:
function launchChallenge(address _positionAddr, uint256 _collateralAmount, uint256 expectedPrice) external validPos(_positionAddr) returns (uint256) { IPosition position = IPosition(_positionAddr); if (position.price() != expectedPrice) revert UnexpectedPrice();
#3 - c4-sponsor
2023-04-29T23:15:58Z
luziusmeisser marked the issue as sponsor confirmed
#4 - hansfriese
2023-05-04T03:08:42Z
Since the owner lower the price of the position, the collateral for a challenge worth nothing, and the challengers might lose their collateral. So I am agree with the sponsor.
#5 - c4-judge
2023-05-04T03:08:57Z
hansfriese marked the issue as satisfactory
#6 - c4-judge
2023-05-18T15:13:00Z
hansfriese marked the issue as selected for report
🌟 Selected for report: decade
Also found by: 0x3b, 0xDACA, 0xWaitress, 0xWeiss, 0xkaju, Arz, Aymen0909, BPZ, EloiManuel, HaCk0, J4de, Jerry0x, Jiamin, John, Juntao, Kek, Lalanda, MiloTruck, Mukund, PNS, RedTiger, Ruhum, Satyam_Sharma, ToonVH, Tricko, Udsen, ak1, anodaram, bin2chen, carrotsmuggler, cccz, circlelooper, deadrxsezzz, giovannidisiena, jasonxiale, joestakey, juancito, karanctf, kenta, kodyvim, ladboy233, lil_eth, lukino, markus_ether, marwen, mrpathfindr, nobody2018, parlayan_yildizlar_takimi, peakbolt, ravikiranweb3, rbserver, rvierdiiev, silviaxyz, volodya, zhuXKET, zzebra83
0.0748 USDC - $0.07
The function restructureCapTable
loops over a list of users and burns their holdings. However, it is incorrectly coded and only burns the first element.
for (uint256 i = 0; i<addressesToWipe.length; i++){ address current = addressesToWipe[0]; //@audit should be i, not 0 _burn(current, balanceOf(current)); }
Since this breaks the purpose of the function, it is classified as high.
Evident from the code.
Manual Review
Replace 0
with i
in the loop.
#0 - c4-pre-sort
2023-04-20T14:16:22Z
0xA5DF marked the issue as duplicate of #941
#1 - c4-judge
2023-05-18T14:23:17Z
hansfriese marked the issue as satisfactory
#2 - c4-judge
2023-05-18T14:32:26Z
hansfriese changed the severity to 2 (Med Risk)
🌟 Selected for report: yellowBirdy
Also found by: BenRai, ChrisTina, GreedyGoblin, Norah, carrotsmuggler
153.271 USDC - $153.27
The function deny()
can be used on any position to cancel it immediately within 3 days of creation (at least). This is implemented to ensure bad positions do not go through.
This function imposes a cooldown on the position until expiry, as shown below.
cooldown = expiration;
This trips off the noCooldown
modifier which checks for the same.
modifier noCooldown() { if (block.timestamp <= cooldown) revert Hot(); _; }
The function withdrawCollateral
is also modified with this modifier, and thus essentially locks down their collateral until the expiration date is passed.
This can be used to cause locked funds or opportunity losses to position openers by any person holding enough equity tokens. Since the position owner is already losing their opening fee, it seems unnecessary to continue to lock the collateral as well until expiry.
Calling deny on any position locks its collateral.
Manual Review
Allow collateral to be withdrawn when denied.
#0 - c4-pre-sort
2023-04-24T07:11:41Z
0xA5DF marked the issue as duplicate of #874
#1 - c4-judge
2023-05-17T18:53:08Z
hansfriese changed the severity to 2 (Med Risk)
#2 - c4-judge
2023-05-18T13:21:58Z
hansfriese marked the issue as satisfactory