[2025-02-25] Double staking reward bug

Summary

A vulnerability was discovered where users staking both directly (solo) and via nomination pools could have their stake amounts overlapping, allowing them to earn double rewards while only staking half of the required total stake.

The immediate mitigation was to prevent users from participating in both systems simultaneously. The root cause was in how pallet-staking handles staking via locks rather than using reserve or hold, which would prevent overlapping of stake.

Impact

  • A staker was able to reuse a portion of their staked funds as a reserve in another pallet.
  • The issue went unnoticed until recent changes introduced delegated staking via nomination pools, increasing the risk of exploitation.
  • With these changes, a user could stake the same funds both as a solo staker and within a nomination pool, effectively receiving 2× staking rewards while only locking 1× the actual funds.

Timeline

  • Feb 26, 2025: Issue first reported by PolkaGate.
  • Feb 26, 2025: Initial patch merged to master (stable2503): #7685.
  • Feb 27, 2025: Patch release of v1.4.1 in the fellowship with the overstake fix backported to 2409: #608.
  • Feb 27, 2025: Runtime upgrade referenda submitted for Kusama (fellowship whitelist) and Polkadot (fellowship whitelist).
  • Feb 28, 2025: Kusama upgraded.
  • Mar 5, 2025: Polkadot upgraded.

Here is a report listing all Polkadot accounts that were overstaked — i.e., receiving rewards for more funds than they actually held — compiled after the fix was applied. This helps identify which accounts, if any, may have exploited the bug. Based on the delta column, there is no indication that the issue was actively abused.

Root Cause

pallet-staking relies on locks, which can overlap with holds from other pallets (e.g., pallet-nomination-pools).

This allowed scenarios where:

  • A user stakes x tokens via solo staking.
  • The same user stakes x tokens via a pool.
  • Despite these being locked and held, the overlapping accounting allowed the user to still withdraw x tokens freely.

Result: A user effectively stakes x tokens but earns rewards for 2x.

Resolution

Temporary Fix:

  • A filter was added to prevent nomination pool users from participating in solo staking, and vice versa.
  • A temporary extrinsic, withdraw_overstake, was introduced. It verifies whether a staker has the correct amount of stake locked and removes any stake positions that cannot be properly locked.

Long-Term Fix:

  • Migrate pallet-staking to use holds instead of locks. This ensures that staked funds are exclusively held and cannot overlap with other locked or frozen funds. This change is included in SDK version stable2503.
  • The filters introduced as part of the temporary fix can be removed once Fellowship runtimes upgrade to SDK stable2503. After that, users will again be able to participate in both solo staking and nomination pools simultaneously.
4 Likes