GoGoPool contest - Manboy's results

Liquid staking for Avalanche.

General Information

Platform: Code4rena

Start Date: 15/12/2022

Pot Size: $128,000 USDC

Total HM: 28

Participants: 111

Period: 19 days

Judge: GalloDaSballo

Total Solo HM: 1

Id: 194

League: ETH

GoGoPool

Findings Distribution

Researcher Performance

Rank: 75/111

Findings: 2

Award: $67.13

🌟 Selected for report: 0

🚀 Solo Findings: 0

Awards

9.9345 USDC - $9.93

Labels

bug
3 (High Risk)
satisfactory
duplicate-213

External Links

Lines of code

https://github.com/code-423n4/2022-12-gogopool/blob/main/contracts/contract/MinipoolManager.sol#L239-L246 https://github.com/code-423n4/2022-12-gogopool/blob/aec9928d8bdce8a5a4efe45f54c39d4fc7313731/contracts/contract/MinipoolManager.sol#L163-L164

Vulnerability details

Impact

If a minipool is in the Withdrawable or Error state (MinipoolStatus), anyone can create a new minipool with the same nodeID (using the createMinipool function). This will prevent the original minipool owner from withdrawing their funds (via withdrawMinipoolFunds) since they will no longer be the owner. The funds will be locked in the contract.

Proof of Concept

At line 206 in MinipoolManagerTest (in the testWithdrawMinipoolFunds function), add:

address hacker = getActorWithTokens("hacker", MAX_AMT, MAX_AMT); vm.startPrank(hacker); ggp.approve(address(staking), MAX_AMT); staking.stakeGGP(ggpStakeAmt); uint256 delegationFee = 0.02 ether; minipoolMgr.createMinipool{value: depositAmt}(mp1.nodeID, 2 weeks, delegationFee, 1000 ether); vm.stopPrank();

This code snippet will create a new minipool with the same nodeID as nodeOp's minipool and make the nodeOp's subsequent withdrawal attempt fail.

Tools Used

Foundry

In the requireValidStateTransition function, the transition from Withdrawable or Error states to the Prelaunch state should not be valid.

#0 - 0xminty

2023-01-04T00:12:53Z

dupe of #805

#1 - c4-judge

2023-01-09T12:37:46Z

GalloDaSballo marked the issue as duplicate of #213

#2 - c4-judge

2023-02-03T12:33:01Z

GalloDaSballo changed the severity to 2 (Med Risk)

#3 - c4-judge

2023-02-03T19:26:10Z

GalloDaSballo changed the severity to 3 (High Risk)

#4 - c4-judge

2023-02-08T08:26:45Z

GalloDaSballo changed the severity to 2 (Med Risk)

#5 - c4-judge

2023-02-08T08:50:12Z

GalloDaSballo changed the severity to 3 (High Risk)

#6 - c4-judge

2023-02-08T20:30:04Z

GalloDaSballo marked the issue as satisfactory

#7 - c4-judge

2023-02-09T08:53:06Z

GalloDaSballo changed the severity to QA (Quality Assurance)

#8 - Simon-Busch

2023-02-09T12:51:40Z

Changed severity back from QA to H as requested by @GalloDaSballo

Findings Information

Labels

bug
2 (Med Risk)
satisfactory
edited-by-warden
duplicate-723

Awards

57.1995 USDC - $57.20

External Links

Lines of code

https://github.com/code-423n4/2022-12-gogopool/blob/main/contracts/contract/MinipoolManager.sol#L528-L533 https://github.com/code-423n4/2022-12-gogopool/blob/aec9928d8bdce8a5a4efe45f54c39d4fc7313731/contracts/contract/MinipoolManager.sol#L290

Vulnerability details

Impact

After the finishFailedMinipoolByMultisig function is called (by a valid mutisig) on a minipool in the Error or Withdrawable state, the node operator will no longer be able to withdraw (via the withdrawMinipoolFunds function) from that minipool.

This is because the finishFailedMinipoolByMultisig function will set the minipool into the Finished state, and in the withdrawMinipoolFunds function, the call to the requireValidStateTransition function will fail, as the transitioning from the Finished state to the Finished state is not a valid state transition.

Also note that the finishFailedMinipoolByMultisig function does not check that the minipool is in the Error state, so it can also be called on a minipool in the Withdrawable state, as Withdrawable -> Finished is a valid state transition. Preventing the node operator from withdrawing.

Proof of Concept

After line 577 in test/unit/MinipoolManager.t.sol (at the end of the testRecordStakingError function), add this code snippet:

// the nodeOp tries to withdraw after the minipool went into the `Error` state, and the `finishFailedMinipoolByMultisig` // function was called by the multisig vm.prank(nodeOp); minipoolMgr.withdrawMinipoolFunds(mp1.nodeID);

This will fail with an InvalidStateTransition error, as the state change from Finished to Finished in the withdrawMinipoolFunds function fails.

Tools Used

Foundry

Remove the finishFailedMinipoolByMultisig function. If required, add a makeWithdrawableFailedMinipoolByMultisig, that lets the multisig transition the minipool state from the Error to then Withdrawable state. This will still allow the node operator to withdraw.

#0 - c4-judge

2023-01-10T10:00:18Z

GalloDaSballo marked the issue as duplicate of #175

#1 - c4-judge

2023-01-29T15:28:54Z

GalloDaSballo marked the issue as duplicate of #723

#2 - c4-judge

2023-02-08T20:13:56Z

GalloDaSballo marked the issue as satisfactory

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