Aurelis← Back to site · aurelis.work@gmail.com

Case study · Solana smart contract

A slashing check that only looked at half the collateral

Project
Paraloom, a privacy-focused Solana L2
Component
slash_validator in the Anchor program
Severity
Medium, under the project's own bounty scale
Report
Issue #1406 · PR #1407

Background

Paraloom validators must lock two kinds of collateral to join: SOL and a protocol token. Registration enforces a minimum for both. Validators then co-sign settlements, and the network needs a supermajority of them to approve.

The bug

When the admin slashes a validator, both balances are reduced by the same percentage. The code then decides whether to deactivate the validator, and that check compared only the SOL balance to its minimum.

- if validator_account.stake_amount < registry.minimum_stake {
+ if validator_account.stake_amount < registry.minimum_stake
+     || validator_account.token_stake_amount < registry.min_token_stake
+ {
      validator_account.is_active = false;
      // residual SOL and token are moved to unbonding
  }

So a validator with extra SOL could be slashed until its token collateral was below the required minimum, and still stay active. It kept counting toward the quorum and kept co-signing, even though it would not have been allowed to register in that state.

Why it matters

The token half exists to make misbehaviour costly. A validator that has been slashed below the token floor but stays active is exactly the case the rule was meant to remove. This is an accounting and invariant failure rather than a direct theft path, which is why I rated it Medium.

The fix and the test

The patch adds the second condition, so dropping below either floor deactivates the validator and moves both residual balances into unbonding. I added an integration test that registers a validator with surplus SOL and the minimum token stake, applies a 25% slash, and asserts that the validator is inactive, the active count and total stake are decremented, and the residual SOL and tokens are in unbonding. I also adjusted one existing test so it still leaves both balances above their floors.

Status: submitted and awaiting maintainer review. I wrote the test against the project's existing test helpers, but I have not run the suite locally, and the project's CI has not yet been approved to run on my pull request.