Developers that use on-chain governance pallets such as elections-phragmen and the pallet-collective pallet need to make a few important configuration and protocol decisions that may affect the security of their governance protocol. Given the configuration flexibility, use cases, and network conditions, it may be hard to reason about second order effects of decisions such as defining the voting bonds, candidate stakes, minimum enactment periods, and how those decisions affect the security of the protocol. This document provides the background and general guidelines for pallet developers to make the best decisions to optimize security when using the elections-phragmen and council pallets (and other governance pallets) based on the lessons from a successful attack on Maganta that happened in October of this year.
The Mangata team has put together a throughout report of the incident. In summary, the attacker gained majority on the council by controlling a subset of voters that elected the attacker’s candidates to become the majority of the council. Once the attacker was in control of the council, they proposed a motion that consisted of a XCM call to transfer all the funds from the KSM parachain sovereign account to the attacker’s account.
Mangata governance model and implementation
The Mangata parachain (KSM) relies on the elections-phragmen and the pallet-collective to implement the council election logic. The sudo origin pallet, which is a fork of the FRAME sudo pallet, allows an elected council majority to dispatch root calls.
At the time of the attack, the governance flow in Mangata was the following:
- At every
TermDuration
blocks, a new voting round starts; - A council of 9 members is selected based on the results of the election;
- The elected majority votes to approve or disapprove the council motion. Once the council motion is backed by a council majority, it is promptly executed;
- An elected majority has executing power and can propose calls as a sudo key account.
Based on the runtime configurations of the elections-phragmen
pallet in Mangata, both the VotingBondBase
and VotingBondFactor
are relatively low. This makes it economically easy for attackers to elect their own candidates. In addition, the sudo_origin
pallet gives root execution to an elected council majority (1).
// (1) sudo-origin pallet runtime configs
impl pallet_sudo_origin::Config for Runtime {
type Event = Event;
type Call = Call;
type SudoOrigin = pallet_collective::EnsureProportionMoreThan<AccountId, CouncilCollective, 1, 2>;
}
The attack surface exploited by the attacker existed due to the compounding of different factors:
- A council has executive power. Since the runtime configs allow the council to execute root actions through the
sudo origin
pallet, the attacker was able to promptly execute a XCM transaction that transferred the funds from the sovereign account in Kusama to their own account. - No delay between a council is elected and when the council is able to propose motions. This delay would give time to the community or parachain operators to decide to kick the rogue elected council;
- A motion is executed right after it is approved by the council, ie., there is no delay between a council motion is approved and its execution. This delay would allow the community or parachain operators to cancel rogue proposed motions;
- Low voting and election bond requirements. This enabled the attacker to elect a rogue council majority easily;
The critical point of attack was that an elected council had executive power which allowed the attacker to execute the XCM message to extract funds from the sovereign account. Even worse, the attacker could have changed the sudo
keys and effectively take over the parachain.
Guidelines to prevent governance attacks
This attack has surfaced the importance of thinking carefully about the configuration of elections and governance protocols.
- Do not give executing power to the council;
- Make sure that the voting bond and/or the minimum number of voters required to elect a majority is high to increase the financial burden for attackers to take over the council.
- Think about setting up an enactment period where the community or a
sudo key
can kick a rogue council and/or cancel a council motion; - Disicentivize attackers by ensuring that the slashable funds held by a council majority cover all the treasury and funds that the council can control. However, this may make it prohibitively expensive for anyone to participate as council member candidates, since the stake per candidate may be too high.
- Emit events to notify and engage the community when a new council is elected.
- Consider slashing voters that voted on rogue councils.
Related follow up ideas/discussions
- Add a new event to collective pallet when a new council is elected (Emit a `MembersSet` event in the collective pallet when a new council is elected · Issue #12621 · paritytech/substrate · GitHub)
- Add optional delays in collective pallet to increase security (Add optional delays in collective pallet to increase security · Issue #12622 · paritytech/substrate · GitHub)
- Add an optional delay between a council being elected and being able to propose motions;
- Add an optional delay between a council motion being approved and executed.