TL;DR
A security hotfix (135955) on the NNS Governance was applied a few hours ago. The source code is now published at commit cbebf5d2 and can be verified, which fixes a security issue. The procedure is done in accordance with the security patch policy defined in a previous motion proposal.
Context
The neuron management proposals can be used by a group of people to jointly manage a neuron. The managed neuron can execute commands according to proposals sent by its (up to 15) followees. Mostly because those proposals can only impact the target neurons (unlike other proposals that can impact the entire network), they are treated differently than other proposals in some ways: (1) their fee is 0.01 ICP, instead of 25 ICP and the proposer doesn’t get it back after adoption (2) the maximum number of such open proposals is 100K, rather than 200.
Problem
It is possible for such manage neuron proposals to occupy a large amount of space, by calling the neuron command MakeProposal
which in turn contains another proposal that can be large. In a normal case, a 25 ICP fee might still be taken if the neuron management proposal is adopted, the managed neuron is instructed to make the proposal, and the managed neuron could lose the 25 ICP if the proposal is rejected. However, the proposer can make the inner proposal invalid or simply make sure that the managed neuron doesn’t have enough fee. In these cases, the proposals still occupy a lot of space but the proposer avoids having to pay the higher fees. If such an attack is carried out, only ~15 ICPs (~1500 proposals) are needed to occupy 3GiB of space (2 MiB per proposal), which can make the NNS Governance hit the 3.5GiB soft limit, and certain operations like creating new neurons and making certain proposals will be rejected by NNS Governance as it enters a degraded mode.
Fix 1: Command Validation
Since this is a security hotfix, we aim to make it as simple as possible. Before creating any neuron management proposal (which occupies the wasm memory space), the NNS Governance will apply more command validation (our analysis showed that those 4 are the only manage neuron commands with unbounded data).:
- check that the neuron management command isn’t MakeProposal/DisburseMaturity, effectively disabling them within neuron management proposals
- for Follow/Disburse, validate that the vec fields within them have reasonable size
Impact of Disabling Commands
-
The DisburseMaturity functionality is not supported yet - if a client sends a DisburseMaturity command directly through the manage_neuron canister method (instead of a neuron management proposal), it will simply fail. However, the canister only performs validation when the neuron management command is about to be performed, which still makes it possible for such neuron management proposals to occupy space.
-
In the last 2 years, only 3 neuron management proposals (134354, 134375) and 135853 were made where the command within them is another proposal.
-
Those 2 proposals are 2 attempts at the same goal, so for all intents and purposes, the use case we are disabling only happened once in the last 2 years. Therefore it seems justified to take it away in a security hotfix.
-
Those proposals are clearly not intended as attacks as mentioned above, since they are not large and there were only 2.
-
We believe that the use case of sending a RegisterKnownNeuron proposal as part of a neuron management proposal is legitimate - while the proposer of a proposal is usually not very important, it does make more sense for the known neuron itself to send out the RegisterKnownNeuron proposal. We will discuss it below in more detail.
Fix 2: Lower # of Open Neuron Management Proposals
We propose to limit the total number of open neuron management proposals to 10K instead of 100K. Our analysis showed that in the last 2 years, there were roughly 7K neuron management proposals. Therefore we believe that this change should not cause inconveniences for the users.
Storage Limit After Hotfix
The 2 changes proposed above lowered the total storage that can be used by all the neuron management proposals, in 2 ways:
- The number of open proposals is changed from 100K to 10K
- The total size of a neuron management proposal changed from 2MiB (message size limit) to 35KiB
After the hotfix, the total storage that can be used by neuron management proposals become < 10K * 35KiB < 350MiB (from 100K * 2MiB ~ 200GiB). Note that the 35KiB is an over-estimation, where the dominant part is the 30KB proposal summary.
Next Steps
Validation on ManageNeuron Commands
In general, we need to consider validating neuron management proposals more carefully. We will propose more changes around validating ManageNeuron commands (currently, the validation logic is mixed with the execution logic) in future proposals.
Request for Feedback: Allow Certain Proposals in the future
Since not all proposals can be large (e.g. the RegisterKnownNeuron proposals have a clear bound), it’s possible to re-enable certain proposals to be made through neuron management proposals in the future, without sacrificing security:
- Allow certain types of proposals to be made within neuron management proposals
- Enforce a size limit of the proposals within the neuron management proposals
However, we believe that the current state of disallowing MakeProposal commands is also the best option going forward. For use cases like RegisterKnownNeuron, such proposals can still be made directly by the proposer (through the manage_neuron canister method), and the to-be known neuron can be instructed to vote on it (either through a neuron management proposal with RegisterVote, or through followee configuration)