New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
malicious validator can cancel other minipools and make honest user loose their initial investment and reward #699
Comments
dupe of #805 |
GalloDaSballo marked the issue as duplicate of #213 |
GalloDaSballo changed the severity to 2 (Med Risk) |
GalloDaSballo changed the severity to 3 (High Risk) |
GalloDaSballo changed the severity to 2 (Med Risk) |
GalloDaSballo changed the severity to 3 (High Risk) |
GalloDaSballo marked the issue as satisfactory |
GalloDaSballo changed the severity to QA (Quality Assurance) |
Changed severity back from QA to H as requested by @GalloDaSballo |
Lines of code
https://github.com/code-423n4/2022-12-gogopool/blob/aec9928d8bdce8a5a4efe45f54c39d4fc7313731/contracts/contract/MinipoolManager.sol#L225
https://github.com/code-423n4/2022-12-gogopool/blob/aec9928d8bdce8a5a4efe45f54c39d4fc7313731/contracts/contract/MinipoolManager.sol#L279
Vulnerability details
A malicious user can abuse
createMinipool
function to become the new minipool owner. He can do this by waiting for a minipool to become withdrawable and then backrun the transaction by making himself the new owner of the minipool and then callcancelMinipool
to retrieve the funds needed to become the owner in the first place.The honest user if is not fast enough will lose the initial investment plus any reward if available.
Impact
Honest validators can loose the minipool ownership and any funds associated with it.
Proof of Concept
For the attack to succeed a malicious user must first create a minipool on their own to bypass this control line in
createMinipool
https://github.com/code-423n4/2022-12-gogopool/blob/aec9928d8bdce8a5a4efe45f54c39d4fc7313731/contracts/contract/MinipoolManager.sol#L225
that can prevent the canceling of the desired minipool
https://github.com/code-423n4/2022-12-gogopool/blob/aec9928d8bdce8a5a4efe45f54c39d4fc7313731/contracts/contract/MinipoolManager.sol#L279
By calling
createMinipool
on an existing minipool the attacker can override the original owner.It also has to wait for the minipool to become withdrawable by listening to the event
MinipoolStatusChanged(nodeID, MinipoolStatus.Withdrawable);
. This is because the targeted minipool has to be in the withdrawable state forcreateMinipool
call to succeed.The following POC can be added to
MinipoolManager.t.sol
unit test fileThe test will show that a malicious validator can cancel out any minipool he targets for the only cost of gas fees.
By running the test
forge test -m testRecordStakingEnd_POC -vv
we can see that the malicious user by creating only one minipool he can cancel out other minipools that not belong to him and as already stated the honest users will lose their initial investment and the ability to use the minipool in the future.[PASS] testRecordStakingEnd_POC() (gas: 9302534) Logs: i 0 Balance attacker before 999000000000000000000000 Minipool owner before 0x0000000000000000000000000000000000050001 Minipool owner after 0x0000000000000000000000000000000000050002 Balance attacker after 999000000000000000000000 i 1 Balance attacker before 999000000000000000000000 Minipool owner before 0x0000000000000000000000000000000000050001 Minipool owner after 0x0000000000000000000000000000000000050002 Balance attacker after 999000000000000000000000 i 2 Balance attacker before 999000000000000000000000 Minipool owner before 0x0000000000000000000000000000000000050001 Minipool owner after 0x0000000000000000000000000000000000050002 Balance attacker after 999000000000000000000000 i 3 ...
Tools Used
forge of foundry
Recommended Mitigation Steps
Check for the original owner inside
createMinipool
call to prevent undesired overridesint256 minipoolIndex = getIndexOf(nodeID); if (minipoolIndex != -1) { + onlyOwner(minipoolIndex); requireValidStateTransition(minipoolIndex, MinipoolStatus.Prelaunch); resetMinipoolData(minipoolIndex); // Also reset initialStartTime as we are starting a whole new validation setUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".initialStartTime")), 0);
The text was updated successfully, but these errors were encountered: