Skip to content
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

Some setters' timelock can be bypassed #698

Open
code423n4 opened this issue Aug 1, 2022 · 4 comments
Open

Some setters' timelock can be bypassed #698

code423n4 opened this issue Aug 1, 2022 · 4 comments
Labels
2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working old-submission-method resolved Finding has been patched by sponsor (sponsor pls link to PR containing fix) selected-for-report This submission will be included/highlighted in the audit report sponsor confirmed Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity")

Comments

@code423n4
Copy link
Contributor

Lines of code

https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/governance/GolomToken.sol#L58-L72
https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/core/GolomTrader.sol#L444-L457
https://github.com/code-423n4/2022-07-golom/blob/7bbb55fca61e6bae29e57133c1e45806cbb17aa4/contracts/rewards/RewardDistributor.sol#L298-L311

Vulnerability details

Impact

MED - Function could be impacted

As the timelock does not work as supposed to work, the owner of the contract can bypass timelock.

  • effected Functions:
    • GolomToken: setMinter, executeSetMinter
    • GolomTrader: setDistributor, executeSetDistributor
    • RewardDistributor: addVoteEscrow, executeAddVoteEscrow

Proof of Concept

The first poc shows to bypass timelock for GolomTrader::setDistributor. The same logic applies for the RewardDistributor::addVoteEscrow.
0. The setDistributor was called once in the beforeEach block to set the initial distributor. For this exploit to work, the setDistributor should be called only once. If setDistributor was called more than once, one can set the distributor to zero address (with timelock like in the GolomToken case, then set to a new distributor after that)

  1. reset distributor to zero address without timelock by calling executeSetDistributor
  2. set a new distributor without timelock by calling setDistributor
  3. Rinse and repeat: as long as setDistributor is not called multiple times in row, the owner can keep setting distributor without timelock.

A little bit different variation of timelock bypass was found in the GolomToken. Although the owner should wait for the timelock to set the minter to zero address, but after that, the owner can set to the new minter without waiting for a timelock. Since the meaning of timelock is to let people know the new minter's implementation, if the owner can bypass that, the timelock is almost meaningless.
The exploitation steps: the second proof of concept

  1. call setMineter with zero address
  2. wait for the timelock
  3. call executeSetMineter to set the minter to zero address
  4. now the onwer can call setMineter with any address and call executeSetMinter without waiting for the timelock

The owner can call executeSetdistributor even though there is no pendingDistributor set before. Also, setDistributor sets the new distributor without timelock when the existing distributor's address is zero.

// GolomTrader
// almost identical logic was used in `RewardDistributor` to addVoteEscrow
// similar logic was used in `GolomToken` to `setMineter`


444     function setDistributor(address _distributor) external onlyOwner {
445         if (address(distributor) == address(0)) {
446             distributor = Distributor(_distributor);
447         } else {
448             pendingDistributor = _distributor;
449             distributorEnableDate = block.timestamp + 1 days;
450         }
451     }
452
453     /// @notice Executes the set distributor function after the timelock
454     function executeSetDistributor() external onlyOwner {
455         require(distributorEnableDate <= block.timestamp, 'not allowed');
456         distributor = Distributor(pendingDistributor);
457     }

Tools Used

None

Recommended Mitigation Steps

To mitigate, execute functions can check whether pendingDistributor is not zero. It will ensure that the setters are called before executing them, as well as prevent to set to zero addresses.

@code423n4 code423n4 added 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working old-submission-method labels Aug 1, 2022
code423n4 added a commit that referenced this issue Aug 1, 2022
@0xsaruman 0xsaruman added sponsor confirmed Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity") sponsor disputed Sponsor cannot duplicate the issue, or otherwise disagrees this is an issue and removed sponsor confirmed Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity") labels Aug 16, 2022
@0xsaruman
Copy link
Collaborator

call setMineter with zero address
wait for the timelock

This alone will trigger awareness that something malicious is happening and since timelock is there people have time to get out.

@0xsaruman
Copy link
Collaborator

the second POC is valid

@0xsaruman 0xsaruman added sponsor confirmed Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity") and removed sponsor disputed Sponsor cannot duplicate the issue, or otherwise disagrees this is an issue labels Aug 18, 2022
@0xsaruman
Copy link
Collaborator

removed all secondary time locks in the contract and only using the primary timelock that will be behind the owner.

@0xsaruman 0xsaruman added the resolved Finding has been patched by sponsor (sponsor pls link to PR containing fix) label Sep 5, 2022
@JeeberC4 JeeberC4 added the selected-for-report This submission will be included/highlighted in the audit report label Oct 21, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working old-submission-method resolved Finding has been patched by sponsor (sponsor pls link to PR containing fix) selected-for-report This submission will be included/highlighted in the audit report sponsor confirmed Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity")
Projects
None yet
Development

No branches or pull requests

3 participants