Skip to content
This repository has been archived by the owner on Mar 3, 2024. It is now read-only.

thekmj - emergency_shutdown role is not enough for emergency shutdown. #1

Open
sherlock-admin2 opened this issue Aug 28, 2023 · 5 comments
Labels
Disagree With Severity The sponsor disputed the severity of this issue Has Duplicates A valid issue with 1+ other issues describing the same vulnerability Medium A valid Medium severity issue Reward A payout will be made for this issue Sponsor Confirmed The sponsor acknowledged this issue is valid Will Fix The sponsor confirmed this issue will be fixed

Comments

@sherlock-admin2
Copy link
Contributor

sherlock-admin2 commented Aug 28, 2023

thekmj

high

emergency_shutdown role is not enough for emergency shutdown.

Summary

There are two protocol roles, emergency_shutdown and cooler_overseer. The emergency_shutdown should have the ability to shutdown the Clearinghouse.

However, in the current contract, emergency_shutdown role does not have said ability. An address will need both emergency_shutdown and cooler_overseer to perform said action.

We have also confirmed with the protocol team that the two roles will be held by two different multisigs, with the shutdown multisig having a lower threshold and more holders. Thereby governance will not be able to act as quickly to emergencies than expected.

Vulnerability Detail

Let's examine the function emergencyShutdown():

function emergencyShutdown() external onlyRole("emergency_shutdown") {
    active = false;

    // If necessary, defund sDAI.
    uint256 sdaiBalance = sdai.balanceOf(address(this));
    if (sdaiBalance != 0) defund(sdai, sdaiBalance);

    // If necessary, defund DAI.
    uint256 daiBalance = dai.balanceOf(address(this));
    if (daiBalance != 0) defund(dai, daiBalance);

    emit Deactivated();
}

This has the modifier onlyRole("emergency_shutdown"). However, this also calls function defund(), which has the modifier onlyRole("cooler_overseer")

function defund(ERC20 token_, uint256 amount_) public onlyRole("cooler_overseer") {

Therefore, the role emergency_shutdown will not have the ability to shutdown the protocol, unless it also has the overseer role.

Proof of concept

To get a coded PoC, make the following modifications to the test case:

//rolesAdmin.grantRole("cooler_overseer", overseer);
rolesAdmin.grantRole("emergency_shutdown", overseer);
  • Run the following test command (to just run a single test test_emergencyShutdown()):
forge test --match-test test_emergencyShutdown

The test will fail with the ROLES_RequireRole() error.

Impact

emergency_shutdown role cannot emergency shutdown the protocol

Code Snippet

https://github.com/sherlock-audit/2023-08-cooler/blob/main/Cooler/src/Clearinghouse.sol#L339
https://github.com/sherlock-audit/2023-08-cooler/blob/main/Cooler/src/Clearinghouse.sol#L360-L372

Tool used

Manual Review, Foundry/Forge

Recommendation

There are two ways to mitigate this issue:

  • Separate the logic for emergency shutdown and defunding. i.e. do not defund when emergency shutdown, but rather defund separately after shutdown.
  • Move the defunding logic to a separate internal function, so that emergency shutdown function can directly call defunding without going through a modifier.
@sherlock-admin
Copy link
Contributor

1 comment(s) were left on this issue during the judging contest.

0xyPhilic commented:

invalid because it can be considered low as roles can be given again and there is no loss of funds

ohmzeus added a commit to ohmzeus/Cooler that referenced this issue Sep 5, 2023
Summary: emergency_shutdown role is not enough for emergency shutdown.
Issue Link: sherlock-audit/2023-08-cooler-judging#1
Fix Description: Refactor defund() into a permissioned external function and an unpermissioned _defund() internal function. emergencyShutdown() interacts with internal function instead of external function to avoid permissioning issue.
0xrusowsky pushed a commit to ohmzeus/Cooler that referenced this issue Sep 7, 2023
* Fix Issue 01

Summary: emergency_shutdown role is not enough for emergency shutdown.
Issue Link: sherlock-audit/2023-08-cooler-judging#1
Fix Description: Refactor defund() into a permissioned external function and an unpermissioned _defund() internal function. emergencyShutdown() interacts with internal function instead of external function to avoid permissioning issue.
@0xrusowsky 0xrusowsky added Sponsor Confirmed The sponsor acknowledged this issue is valid Disagree With Severity The sponsor disputed the severity of this issue Will Fix The sponsor confirmed this issue will be fixed labels Sep 9, 2023
@0xrusowsky
Copy link

fair point, but it still should be low as a user can have several roles

@Oot2k
Copy link
Collaborator

Oot2k commented Sep 9, 2023

I have to disagree, a user can indeed have several roles, but that can not be ensured/ if there are two separate roles they should be considered separate.

@sherlock-admin sherlock-admin changed the title Breezy Myrtle Anteater - emergency_shutdown role is not enough for emergency shutdown. thekmj - emergency_shutdown role is not enough for emergency shutdown. Sep 12, 2023
@sherlock-admin sherlock-admin added the Reward A payout will be made for this issue label Sep 12, 2023
@ohmzeus
Copy link

ohmzeus commented Sep 13, 2023

Fix: ohmzeus/Cooler#50

@jkoppel
Copy link
Collaborator

jkoppel commented Sep 16, 2023

Fix confirmed.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Disagree With Severity The sponsor disputed the severity of this issue Has Duplicates A valid issue with 1+ other issues describing the same vulnerability Medium A valid Medium severity issue Reward A payout will be made for this issue Sponsor Confirmed The sponsor acknowledged this issue is valid Will Fix The sponsor confirmed this issue will be fixed
Projects
None yet
Development

No branches or pull requests

6 participants