Security Patch NNS Governance Neuron Aging 2023-07-17


On the evening of Sunday, July 9th, a neuron was reported with an impossibly large age. This indicated an issue with some logic related to aging and merging neurons.


During the investigation, the team discovered two additional issues with regard to aging.

  1. A dissolved neuron that originally had a positive dissolve delay was able to age in a Dissolved state. This allowed for a neuron to be able to be disbursed at any time, and if increase_dissolve_delay was called, it would retain its age, thus giving it voting power it should not have had.
  2. update_stake, which is called by refresh_neuron, was not taking Neuron’s DissolveState into account, which allowed a dissolved neuron to get an age bonus when stake was added to a dissolved or a dissolving neuron.

These allowed a neuron (that went from NotDissolving to a Dissolved state) to retain an age bonus after refresh_neuron is called. As a result of this, a neuron was able, in these circumstances, to get more voting power than is justified based on the time its stake was in a NotDissolving state with a positive dissolve delay.

This constituted a security risk to the fair governance of the NNS.


The solution to the two problems is as follows:

  1. No longer use the timestamp in WhenDissolvedTimestampSeconds(ts) to set the aging_since_timestamp_seconds field during increase_dissolve_delay, but instead to set it to the current time (as done, e.g., when transitioning from other equivalently dissolved neuron states to “NotDissolving”).
  2. Check the dissolve state of the neuron in update_stake, and set aging_since_timestamp_seconds to u64::MAX when the neuron is in a WhenDissolvedTimestampSeconds state.

Link to proposal: Proposal: 123485 - ICP Dashboard