Sec3 logo — Solana smart contract security firm
Back to Blog
Tools

Solana Stake Pool: A Semantic Inconsistency Vulnerability Discovered by X-Ray

Sec3 Research Team

sec3 team recently discovered a vulnerability in the official stake-pool program of solana-program-library. The vulnerability has been patched in this PR. Thanks @joncinque for the swiftest action confirming with us and fixing the issue.

This article describes our journey in discovering the vulnerability and constructing the PoC via penetration testing.

We note that the stake-pool code was audited before by multiple companies. This article motivates the need of a more comprehensive and systematic audit process (e.g., through automated analysis and verification tools as adopted by sec3 team).

What’s the vulnerability: inconsistent initialization

Solana’s stake-pool program is used to pool together SOL and redistribute the stakes across the network, to maximize censorship resistance and rewards.

The issue has been fixed (PR on GitHub)

Screenshot of the GitHub pull request description:

Problem

If a pool creator puts too many lamports in the reserve account on creation, those are essentially lost. This behavior is unclear.

Solution

Credit the additional reserve lamports as pool tokens on init.

Big thanks to @soteria-bc / Soteria for reporting this issue!

joncinque added 3 commits 4 days ago

stake-pool: Mint extra reserve lamports as pool tokens on init (9a66848)

The vulnerability lies in the stake-pool’s _process`initialize` instruction:

> During initialization, it did not issue tokens for the lamports in the reserve stake account. As a result, if the reserve account has any excess funds on creation, the money will be delegated/represented by the tokens issued for the very first deposit. If this deposit is made by an attacker (for example via a front run), the money in the reserve will be stolen.

The issue is subtle because the pool creator may mistakenly put excess lamports into the reserve stake account, and this behavior is undefined. The vulnerability won’t surface if either the initial reserve account has no money or the first depositor is the pool creator.

Important Notice: Since the stake-pool program has been forked, reused, or modified by other Solana projects, the vulnerable code might have been widely deployed. Please be sure to apply the patch if you are using stake-pool.

How we discovered the vulnerability: semantic inconsistency

sec3 team was experimenting a new checker in our toolbox (an earlier prototype was released here). The new checker exhaustively looks at every path in the code and detects semantic inconsistency issues:

If two things often come together then likely there is a hidden invariant (at the logic or semantic level), and a violation of this invariant (say one of them is missing or in a different order) triggers a warning.

In stake-pool, there exists such an invariant: whenever the reserve_stake account is used (read or write) in an instruction, spl_token::instruction (mint_to, transfer or burn) will also be used in the same instruction.

However, in the _process`initialize instruction before the patch, the [reserve_stake\_account is used](https://github.com/joncinque/solana-program-library/blob/5afe6038e8d1c325b226670046ba72fa9cb8bde4/stake-pool/program/src/processor.rs#L636-L638) (**line 637**), but there exists no use of _spl\token::instruction.` Therefore, our checker flags a semantic inconsistency.

The use of reserve_state account in process_initialize in stake-pool.

636        let stake_state = try_from_slice_unchecked::<stake::state::StakeState>(
637            &reserve_stake_info.data.borrow(),
638        )?;

The PoC (proof of concept)

Based on the reported semantic inconsistency issue above, we proceeded to construct a PoC via penetration testing (more detail on penetration testing techniques can be found in our prior blog Part 3: penetration testing).

The first step is to initialize the stake pool:

In the above, the reserve_stake account is initialized with 100 Sol:

Next, the hacker deposits 1.0 Sol into the stake pool and claims 990000000 pool tokens (which is far more than the expected token amount):

spl_token::instruction::mint_to amount: 990000000

Finally, the hacker burns all their pool tokens and withdraws all the money:

[*] Initialize stake pool!
stake_pool_program: SPoo1Ku8WFXoNDMHPsrGSTSG1Y47rzgn41SLUNakuHy
stake_pool: KoooVyhdpoRPA6gpn7xr3cmjqAvtpHcjcBX6JBKu1nf
withdraw_authority_key: GZZz49yJujbQSU95B3xADbzAyTNiDLpx5eyj5KH4b8By
reserve_stake: Koo4QPbasfYsgf6xbWLhEtmNY2yRTbwBtS1wE4rwutV
hacker: Ko42K5AvQy5HZdnH2ciw1sEzMfWyuMaMUUuJeyP9ViF
dest_user: Ko43FJW4gnEbJ4u5ZbYs1DgW97rrakg3U4Vmrryhddd
manager_fee: Koo6Nqx5Qa8kL8YoYQ3Gfo9dccaPTuNjZpEX9dtJGYR
pool_mint: Koo5cBrFc5KkrS6VDzYDShnMQLc9XUcQ8z72Prpa8wH
deposit_authority_key: EuzWYQJZ5cafZhcdF5rm6gZzMoFi7sF7BAv8cy2RN73k
[*] DepositSol!
[*] WithdrawSol!
Hacker's initial lamports: 1100000000
Hacker's final  lamports: 99090100000

The hacker successfully exploited the vulnerability and stole (99090100000–1100000000) lamports = 97.9901 Sol (see above).

sec3 Audit

sec3 is founded by leading minds in the fields of blockchain security and software verification.

We are pleased to provide audit services to high-impact Dapps on Solana. Please visit sec3.dev or email contact@sec3.dev

How to audit Solana smart contracts series?

For all blogs by sec3, Please visit https://www.sec3.dev/blog

Related Posts

Tools

Announcing sec3 WatchTower

sec3 announces the first release of WatchTower: an in-situ threat monitoring service for Solana smart contracts to detect, prevent and stop security attacks in real time.

Read more
Tools

Announcing sec3 X-ray Security Scanner

sec3 X-ray scanner software is a security scanner specifically designed for Solana smart contracts. sec3 X-ray can detect more than 50 types of security vulnerabilities and can be integrated into the GitHub CI development process. Integrating sec3 X-ray into your protocol's development process can shift security practices left, reduce costly security issues, and speed up time-to-market. sec3 Xray has been adopted at leading Solana Protocols; try it out today!

Read more
Tools

CashioApp Attack - What’s the Vulnerability and How Soteria Detects It

The Cashio stablecoin (CASH) protocol recently lost $50M in an attack. The attacker was able to mint 2,000,000,000 CASH tokens for almost free. The root cause is a vulnerability in the Cashio’s brrr smart contract. Soteria team conducted an in-depth analysis of the attack. Importantly, the vulnerability can be automatically detected by Soteria’s Premium Auto Auditor. This article elaborates on the details.

Read more