OpenZeppelin Governor Denial of Service Cover

OpenZeppelin Governor Denial of Service

Coinspect found a vulnerability in the latest version of the Governor contract provided by OpenZeppelin. This vulnerability would allow an attacker to halt proposals sent to a governance protocol using the latest version of OpenZeppelin’s suite.

The vulnerability was introduced on Jan 26, 2023 and was part of the latest OZ release 4.9.0.

We reported the issue to OpenZeppelin via their bug bounty program on May 30 (like we did when we found Arbitrum’s issue in governance). OpenZeppelin acknowledged the problem quickly and after discussion and collaboration on the fix, it was released on version 4.9.1 of OpenZeppelin’s contracts.

What made the attack possible was the exposure of the cancel function, which used to be internal:

    /**
     * @dev See {IGovernor-cancel}.
     */
    function cancel(uint256 proposalId) public virtual override {
        require(state(proposalId) == ProposalState.Pending, "Governor: too late to cancel");
        require(_msgSender() == _proposals[proposalId].proposer, "Governor: only proposer can cancel");
        _cancel(proposalId);
    }

The exposed cancel method allows a malicious user to disrupt the governance proposal process by leveraging the way proposalIds are calculated. There are two participants involved in the attack: an attacker that does not want a proposal to pass and a proposer that wants to submit a new proposal.

  • The proposer sends their proposal to the network
  • The attacker frontruns their transaction, submitting the exact same proposal
  • As soon as possible, the attacker calls cancel on their proposal

See that the attacker can continue performing the attack as long as they wish. Each time the cost is only two transactions, one of which must be a frontrun. This cost is negligible for proposals which seriously impact the working of a protocol.

OpenZeppelin decided to address the issue by allowing proposers to append their address to the end of a proposal’s description. If a proposer does this, the proposalId is now linked to their address. An attacker can still try to frontrun the proposal, but they would get a different proposalId. It is important to note that proposers are allowed but not forced to do this, so an unaware proposer is still be vulnerable to the attack. Frontends for governance protocols will also still use the vulnerable path in the code until they update.

Read the Security Advisory.

Run a governance?

At Coinspect, we are dedicated to the security of decentralized systems and can assist in auditing your protocols and enforcing safeguards. So reach out to us today.