EigenLayer Contest - Cyfrin's results

Enabling restaking of staked Ether, to be used as cryptoeconomic security for decentralized protocols and applications.

General Information

Platform: Code4rena

Start Date: 27/04/2023

Pot Size: $90,500 USDC

Total HM: 4

Participants: 43

Period: 7 days

Judge: GalloDaSballo

Id: 233

League: ETH

EigenLayer

Findings Distribution

Researcher Performance

Rank: 4/43

Findings: 2

Award: $3,177.34

๐ŸŒŸ Selected for report: 1

๐Ÿš€ Solo Findings: 0

Findings Information

๐ŸŒŸ Selected for report: Cyfrin

Also found by: Josiah, QiuhaoLi, RaymondFam

Labels

bug
2 (Med Risk)
primary issue
selected for report
M-01

Awards

2649.0852 USDC - $2,649.09

External Links

Lines of code

https://github.com/code-423n4/2023-04-eigenlayer/blob/5e4872358cd2bda1936c29f460ece2308af4def6/src/contracts/core/StrategyManager.sol#L197 https://github.com/code-423n4/2023-04-eigenlayer/blob/5e4872358cd2bda1936c29f460ece2308af4def6/src/contracts/core/StrategyManager.sol#L513 https://github.com/code-423n4/2023-04-eigenlayer/blob/5e4872358cd2bda1936c29f460ece2308af4def6/src/contracts/pods/EigenPod.sol#L293 https://github.com/code-423n4/2023-04-eigenlayer/blob/5e4872358cd2bda1936c29f460ece2308af4def6/src/contracts/pods/EigenPod.sol#L396

Vulnerability details

Description

In EigenLayer, watchers submit over-commitment proof in the event a staker's balance on the Beacon chain falls below the minimum restaked amount per validator. In such a scenario, stakersโ€™ shares are decreased by the restaked amount. Note that when a full withdrawal is processed, stakersโ€™ deducted shares are credited back to allow for a planned withdrawal on EigenLayer

If such a staker has delegated to an operator who gets slashed on EigenLayer, there is a possibility that this staker completely bypasses any slashing penalties. If overcommitment reduced the shares in the stakers account to 0, there is nothing available for governance to slash.

It is reasonable to assume that governance calls StrategyManager::slashShares to reduce a percentage of shares (penalty) from all stakers who delegated to a slashed operator and then resets the frozen status of operator by calling ISlasher::resetFrozenStatus.

By simply unstaking on the beacon chain AFTER slashing is complete (and operator is unfrozen), an over-committed staker can simply unstake on beacon chain and get back their shares that were deducted when over-commitment was recorded (refer to PoC). Note that these shares have not faced any slashing penalties.

Impact

An over-committed staker can avoid being slashed in a scenario in which their stake should be subject to slashing and so we evaluate the severity to MEDIUM.

Proof of Concept

Consider the following scenario with a chain of events in this order:

  1. Alice stakes 32 ETH and gets corresponding shares in BeaconEthStrategy.
  2. After some time, Alice gets slashed on the BeaconChain and her current balance on the Beacon Chain is now less than what she restaked on EigenLayer.
  3. An observer will submit a proof via EigenPod::verifyOverCommittedStake and Alice's shares are now decreased to 0 (Note: this will be credited back to Alice when she withdraws from the Beacon Chain using EigenPod::verifyAndProcessWithdrawal)
  4. Next, Alice's operator gets slashed and her account gets frozen.
  5. Governance slashes Alice along with all stakers who delegated to slashed operator (there is nothing to slash since Alice's shares are currently 0).
  6. After slashing everyone, governance resets frozen status of operator by calling ISlasher::resetFrozenStatus.
  7. Alice now unstakes on the Beacon Chain and gets a credit of shares that were earlier deducted while recording over-commitment.
  8. Alice queues a withdrawal request and completes withdrawal without facing any slashing penalty.

Tools Used

Manual review

Over-commitment needs to be accounted for when slashing such that a staker is being slashed not just shares in their account, but also the amount that is temporarily debited while recording over-commitment.

Consider adding a mapping to StrategyManager that keeps track of over-commitment for each staker and take that into consideration while slashing in StrategyManager::slashShares.

Assessed type

Other

#0 - c4-pre-sort

2023-05-09T13:31:51Z

0xSorryNotSorry marked the issue as duplicate of #210

#1 - c4-judge

2023-06-01T15:04:45Z

GalloDaSballo marked the issue as not a duplicate

#2 - c4-judge

2023-06-01T15:04:51Z

GalloDaSballo marked the issue as primary issue

#3 - c4-judge

2023-06-01T15:05:36Z

GalloDaSballo marked the issue as selected for report

#4 - GalloDaSballo

2023-06-01T15:06:56Z

The Warden has shown how, due to an incorrect assumption, it's possible for an over-commited staker to avoid a slashing

The finding requires multiple external requirements:

  • Being over-commited (perhaps inactivity leak or ETH2 slashing)
  • Having delegated to an operator that will be slashed

For these reasons I agree with Medium Severity

Findings Information

Labels

bug
grade-a
high quality report
QA (Quality Assurance)
Q-04

Awards

528.2547 USDC - $528.25

External Links

[L-01] Endian::fromLittleEndianUint64 allows unsafe casting

Description

The input to Endian::fromLittleEndianUint64 is not validated. It should check that the number to be cast is not greater than 2^64 in little endian notation.

Impact

In the event this library is used to cast a number greater that 2^64, the casting will be done incorrectly; however; this is not currently the case and so we evaluate this as LOW.

Proof of Concept

For instance, if this library attempts to cast 2^65 in little endian, the output will be 1 in big endian.

Add the corresponding check to revert for casting of numbers greater than 2^64 in little endian:


    // In Endian.fromLittleEndianUint64(bytes32)
+ if(n & 0xFFFFFFFFFFFFFFFF000000000000000000000000000000000000000000000000 != n){
+ return ERROR_LITTLE_ENDIAN_UNSAFE_UINT64_CAST()
+ }
    n = uint64(uint256(lenum >> 192));
    //...

[NC-01] EigenPod::stake: should be refactored to allow any stake and not just 32 ether

EigenPod::stake, callable only through EigenPodManager::stake, allows the caller to stake 32 ether only, no more or less.

According to the sponsor, it is valid that a user could stake a different amount through the ETH2Deposit contract if they really wanted to. Therefore, to improve UX, this function can be refactored to allow ether deposits of any value.

[NC-02] Rename EigenPod::mostRecentWithdrawalBlockNumber to mostRecentWithdrawalBeforeRestakingBlockNumber

EigenPods essentially switch between 2 modalities, with only (1) possible before launch of the EigenLayer Beacon Chain Oracle: \1) users can re-point withdrawal credentials but not yet prove they have been re-pointed via the EigenPod::verifyWithdrawalCredentialsAndBalance. Partial & full withdrawals will increment their EigenPod balance, and they can then call EigenPod::withdrawBeforeRestaking to withdraw any ETH in the EigenPod. Once a user proves re-pointing of withdrawal credentials for the first time (which must be proven after EigenPod::mostRecentWithdrawalBlockNumber because they could have repointed => withdrawn => used the ETH for something else prior to EigenPod::mostRecentWithdrawalBlockNumber) then the modality is switched to: \2) users can no longer call EigenPod::withdrawBeforeRestaking and must use EigenPod::withdrawRestakedBeaconChainETH.

Therefore, EigenPos::mostRecentWithdrawalBlockNumber should be more properly called mostRecentWithdrawalBeforeRestakingBlockNumber.

#0 - c4-pre-sort

2023-05-09T14:34:23Z

0xSorryNotSorry marked the issue as high quality report

#1 - GalloDaSballo

2023-06-02T09:06:29Z

[L-01] Endian::fromLittleEndianUint64 allows unsafe casting R, similar to adding check for bytes%32 in merkle functions

[NC-01] EigenPod::stake: should be refactored to allow any stake and not just 32 ether R, I can see scenarios in which this would useful (e.g. getting slashed and wanting to top up)

[NC-02] Rename EigenPod::mostRecentWithdrawalBlockNumber to mostRecentWithdrawalBeforeRestakingBlockNumber R

#2 - GalloDaSballo

2023-06-02T09:06:34Z

3R unique report

#3 - c4-judge

2023-06-02T09:38:49Z

GalloDaSballo marked the issue as grade-b

#4 - GalloDaSballo

2023-06-08T10:56:16Z

A after adding DUPS

#5 - c4-judge

2023-06-08T10:56:19Z

GalloDaSballo marked the issue as grade-a

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