Assessment reports>Pye>Critical findings>Uninitialized stake account can be stolen
Category: Coding Mistakes

Uninitialized stake account can be stolen

Critical Impact
Critical Severity
Medium Likelihood

Description

After a solo validator bond has matured, a user can call the counter_party_update_liquid_reserve instruction to unstake lamports from the bond's stake account. These lamports are moved into the bond's liquid reserve and can be later used by the global counter party to redeem their staking tokens.

The amount unstaked is based on the amount of staking tokens held by the global counter party. If unstaking this amount would leave the bond's stake account below the minimum delegation amount, then the entire stake account is unstaked:

let stake_account_lamports = ctx.accounts.stake_account.lamports();
let source_stake_after_split = stake_account_lamports
    .saturating_sub(lamports_to_unstake)
    .saturating_sub(stake_rent);

lamports_to_unstake = if source_stake_after_split < minimum_stake_account_amt {
    stake_account_lamports
} else {
    lamports_to_unstake
};

Then, the lamport amount is split from the bond's stake account into the transient stake account to be later withdrawn into the bond and used by the global counter party.

The issue arises when the entire balance of the bond's stake account is unstaked, as the stake account is deinitialized if it has zero balance after the split. Just as in Finding ref, this leaves a stake account uninitialized where it will be closed once the transaction is finished.

An attacker could stop the stake account from being closed by sending enough lamports for rent in the same transaction, which leaves it uninitialized, allowing them to then reinitialize the stake account to steal it.

Impact

The lamport amount of the bond's stake account is also included in the yield calculations, so an attacker could exploit this issue to drain the global counter party.

Recommendations

Rework the yield calculations to only take into account the balance of the bond's stake account if it is the withdrawer authority.

Remediation

This issue has been acknowledged by Pye in the Sky Labs Ltd., and a fix was implemented in commit d093b983.

Zellic © 2025Back to top ↑