Renzo - aslanbek's results

A protocol that abstracts all staking complexity from the end-user and enables easy collaboration with EigenLayer node operators and a Validated Services (AVSs).

General Information

Platform: Code4rena

Start Date: 30/04/2024

Pot Size: $112,500 USDC

Total HM: 22

Participants: 122

Period: 8 days

Judge: alcueca

Total Solo HM: 1

Id: 372

League: ETH

Renzo

Findings Distribution

Researcher Performance

Rank: 87/122

Findings: 3

Award: $0.41

🌟 Selected for report: 0

🚀 Solo Findings: 0

Awards

0.4071 USDC - $0.41

Labels

bug
3 (High Risk)
satisfactory
sufficient quality report
upgraded by judge
edited-by-warden
:robot:_00_group
duplicate-326

External Links

Lines of code

https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/Withdraw/WithdrawQueue.sol#L219-L233

Vulnerability details

Impact

When requesting a withdrawal, the amount of collateral that will be withdrawn is set at the moment of request, and never changes afterwards. Therefore, regardless of slashings during the coolDownPeriod, the requester will be able to claim exactly the requested amount.

Proof of Concept

  1. ezETH holder Alice notices a slashing from an AVS;
  2. Alice requests redemption of her ezETH for a collateral token;
  3. Slashing is executed;
  4. While every other ezETH holder is affected by the slasing, Alice is not; and she claims her withdrawal once the cooldown period is over.

ezETH exchange rate should be computed at the moment of claiming the withdrawal, not at the moment of request.

Assessed type

MEV

#0 - c4-judge

2024-05-16T10:57:49Z

alcueca marked the issue as satisfactory

#1 - c4-judge

2024-05-16T11:01:20Z

alcueca marked the issue as duplicate of #326

#2 - c4-judge

2024-05-24T10:26:53Z

alcueca changed the severity to 3 (High Risk)

Lines of code

https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/RestakeManager.sol#L318

Vulnerability details

Impact

RestakeManager#calculateTVLs computes the total value of assets stored in the system:

For each OperatorDelegator, for each collateral token, it retrieves OD's balance and adds its ETH value to the total sum;

At i = 0 (first OD), totalWithdrawalQueueValue is being computed by iterating through each token (j= 0, 1, ..., tokenLength - 1):

                if (!withdrawQueueTokenBalanceRecorded) {
                    totalWithdrawalQueueValue += renzoOracle.lookupTokenValue(
                        collateralTokens[i],
                        collateralTokens[j].balanceOf(withdrawQueue)
                    );
                }

Since the first parameter of lookupTokenValue is the address of the token, and the second is its amount, each token will be accounted with the price of the first one.

Proof of Concept

Imagine there's 5 ODs, and 3 collateral tokens: stETH, wbETH, mETH.

Let's debug the first iteration of the external loop:

        for (uint256 i = 0; i < odLength; ) {
            /* ... */
            for (uint256 j = 0; j < tokenLength; ) {
                /* ... */
                if (!withdrawQueueTokenBalanceRecorded) {
                    totalWithdrawalQueueValue += renzoOracle.lookupTokenValue(
                        collateralTokens[i],
                        collateralTokens[j].balanceOf(withdrawQueue)
                    );
                }

                unchecked {
                    ++j;
                }
            }
            /* ... */
            totalWithdrawalQueueValue = true;
        }

i = 0, j = 0 - totalWithdrawalQueueValue is increased by stETH's value, using stETH's price. i = 0, j = 1 - totalWithdrawalQueueValue is increased by WithdrawalQueue's wbETH balance; still using stETH price. i = 0, j = 2 - totalWithdrawalQueueValue is increased by WithdrawalQueue's wbETH balance; still using stETH price.

Attack example

Imagine there's 10 stETH in the system; collateralTokens = [mETH, stETH]; 1 mETH = 1.1 ETH, 1 stETH = 1 ETH;

  1. Alice deposits 1 stETH and receives 1 ezETH.
  2. Bob deposits 1 mETH. calculateTVLs wrongly returns 1.1 ETH. Bob gets 1 ezETH.
  3. Alice withdraws her 0.9090... ezETH. calculateTVLs wrongly returns 2.2 ETH. Alice receives her 1 stETH back, and has 0.090909... ezETH remaining, which she then redeems for mETH, effectively stealing Bob's deposited collateral.
                if (!withdrawQueueTokenBalanceRecorded) {
                    totalWithdrawalQueueValue += renzoOracle.lookupTokenValue(
-                       collateralTokens[i],
+                       collateralTokens[j],
                        collateralTokens[j].balanceOf(withdrawQueue)
                    );
                }

Assessed type

Other

#0 - c4-judge

2024-05-16T10:28:48Z

alcueca marked the issue as satisfactory

#1 - c4-judge

2024-05-16T10:38:47Z

alcueca changed the severity to 2 (Med Risk)

#2 - c4-judge

2024-05-16T10:39:08Z

alcueca changed the severity to 3 (High Risk)

#3 - c4-judge

2024-05-20T04:26:26Z

alcueca changed the severity to 2 (Med Risk)

#4 - c4-judge

2024-05-23T13:47:20Z

alcueca changed the severity to 3 (High Risk)

Awards

0 USDC - $0.00

Labels

bug
downgraded by judge
grade-b
QA (Quality Assurance)
satisfactory
sufficient quality report
edited-by-warden
:robot:_114_group
Q-39

External Links

Lines of code

https://github.com/code-423n4/2024-04-renzo/blob/519e518f2d8dec9acf6482b84a181e403070d22d/contracts/RestakeManager.sol#L274

Vulnerability details

Impact

DepositQueue is expected to receive rewards in any of the collateral tokens. They are expected to be forwarded to OperatorDelegators via sweepERC20.

As the collateral balances of DepositQueue are not included in RestakeManager#calculateTVLs, one can monitor DepositQueue#sweepERC20 transactions, deposit before them, initiate the withdrawal right after (at a higher ezETH exchange rate), and claim it after coolDownPeriod, stealing rewards from honest depositors who have been holding ezETH for a significantly longer duration.

Proof of Concept

  1. Alice sees a sweepERC20 transaction in the mempool;
  2. Alice deposits ETH and mints ezETH;
  3. sweepERC20 transaction is mined;
  4. Alice starts a withdrawal of her ezETH at a higher price, and claims it after coolDownPeriod.

Include DepositQueue's balance in calculateTVL's, minus the fee that would be deduced during sweepERC20.

Assessed type

Other

#0 - c4-judge

2024-05-16T05:47:32Z

alcueca marked the issue as not a duplicate

#1 - c4-judge

2024-05-16T05:47:39Z

alcueca changed the severity to 3 (High Risk)

#2 - c4-judge

2024-05-16T05:47:51Z

alcueca marked the issue as duplicate of #326

#3 - c4-judge

2024-05-16T05:56:53Z

alcueca changed the severity to 2 (Med Risk)

#4 - c4-judge

2024-05-17T12:47:56Z

alcueca marked the issue as satisfactory

#5 - c4-judge

2024-05-24T10:26:55Z

alcueca changed the severity to 3 (High Risk)

#6 - aslanbekaibimov

2024-05-26T12:00:45Z

@alcueca

I believe this should be a duplicate of #383 as long as #383 is a separate issue from #326.

The root cause is "DepositQueue ERC20 balances are not accounted in TVL", and the attack path is "sandwiching sweepERC20".

#7 - c4-judge

2024-05-27T10:02:19Z

alcueca marked the issue as not a duplicate

#8 - c4-judge

2024-05-27T10:02:28Z

alcueca changed the severity to QA (Quality Assurance)

#9 - c4-judge

2024-05-27T10:02:32Z

alcueca marked the issue as grade-b

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter