October 26, 2026
Auditing Smart Contracts on Solana
Account validation, program-derived addresses, cross-program calls, and the risks behind Solana protocol accounting.
Author:
Tigran PiliposyanIn short: Solana programs keep state in separate accounts that each transaction passes in, so a Solana audit checks whether the program verifies those accounts, the authorities and addresses behind them, the programs it calls, and the tokens, prices and shares involved. Certora’s Solana audits have found missing authorization checks, oracle update failures, share-pricing flaws and accounting errors that only appear across multiple operations.
In one Certora audit of Lulo, the deposit_pool instruction required the owner’s signature but never checked that the signer matched the owner recorded in the UserAccount it modified. An attacker could deposit a minimal amount into another user’s account that had no referrer set, name themselves as the referrer, and collect the referral fees on later deposits by that user. The attack repeated across every such account. Lulo fixed the issue.
What a Solana audit follows through one instruction
Every instruction receives its accounts from the transaction. The audit checks each relationship the program relies on, then checks the state that results.
deposit_poolAfter execution
Invariants have to hold after every instruction that can change the state, and across sequences of operations.
Certora findings: first-depositor share-price manipulation (Kamino Vault) · swap output that differs from the estimate (Manifest) · a closed reward pool that blocks deposits and withdrawals (Fragmetric)
Solana programs do not store their state inside the program itself. State lives in separate accounts, which are passed to instructions when they execute. A program must validate those accounts and establish that they represent the state it is supposed to modify. Many Solana security issues come down to getting those relationships wrong.
This is different from the contract storage model used by the Ethereum Virtual Machine (EVM). Stellar’s Soroban expires contract state through a time-to-live (TTL) limit, as covered in Auditing Smart Contracts on Stellar, and Daml writes authorization into the contract through signatories and controllers, as covered in Auditing Smart Contracts on Canton. Solana checks authorization per instruction, through the accounts each transaction supplies, so account ownership, program-derived addresses, signer privileges, and cross-program invocations (CPIs) all affect how a program can access and modify state. An audit needs to follow those relationships through the protocol, especially when several programs work together. The Solana documentation provides an overview of the account and execution models.
Certora has audited Solana protocols across lending, vaults, trading, and restaking. Some findings came from missing authorization checks; others involved oracle updates, share pricing, and accounting across multiple operations. These are useful examples because they show how a small implementation mistake can affect the protocol's economic behavior.
How should Solana programs validate accounts?
An instruction receives the accounts it needs from the transaction. The program cannot assume that a supplied account belongs to the intended user or market just because the account is valid and the transaction was signed.
The Lulo finding above is an instance of this gap.
Checking a signature is not the same as checking authorization for a particular operation. The signer proved control of their own key. The program still needed to verify that the signer was entitled to act on the supplied account.
Account validation also matters when a protocol accepts token accounts, mints, pools, or configuration accounts as instruction inputs. A token account may be valid but belong to a different mint. A pool may exist but refer to another market. The program needs to check the relationships that its business logic relies on.
Frameworks such as Anchor provide constraints including owner, address, has_one, and seeds to express these checks. The Anchor account constraints reference describes the available mechanisms. The audit still needs to establish that the constraints match the protocol's intended authorization model.
What should an audit check about program-derived addresses (PDAs) on Solana?
Program-Derived Addresses (PDAs) are deterministic addresses derived from a program ID and a set of seeds. They have no private key. The program that derives a PDA can authorize it as a signer during a cross-program invocation by using invoke_signed. PDAs are commonly used for vault authorities, user positions, pool state, and other program-controlled accounts. See the Solana PDA documentation.
The seeds determine which logical account a PDA represents. If a program derives an address using the wrong user, market, or mint, it may operate on state belonging to a different context. The program also needs to use the canonical bump when deriving addresses. Accepting a non-canonical bump can allow multiple addresses for the same intended seed set, which may break assumptions about account uniqueness.
An audit needs to check both the derivation itself and the data stored at the resulting address.. A correct PDA does not prove that every other account supplied to the instruction belongs to the same user or market. Nor does it prove that the account's stored fields are consistent with the address.
The audit should follow the PDA from creation through every instruction that reads or modifies it, including CPIs. In particular, it should establish exactly which program can sign for the PDA and which operations that authority enables.
Where do cross-program invocations (CPIs) introduce risk on Solana?
Solana programs can invoke other programs during execution. This composability is used throughout DeFi: a protocol may call a token program to transfer assets, an oracle integration to read prices, or an order book to execute a trade. Signer and writable privileges are passed to the called program, subject to the runtime's privilege checks. The mechanics are described in the CPI documentation.
The security question is whether the caller validates the operation it is asking the other program to perform and accounts for the result it actually receives.
Certora’s Manifest audit found a High severity case. For Token-2022 mints, the withdraw instruction built its token transfer with the source and destination reversed, so a withdrawal moved funds from the user to the vault. Instead of receiving their funds, the user was charged the same amount again. The issue violated Certora’s formal rules for withdrawals and was fixed.
The audit needs to follow the operation across the call boundary and check the resulting balances, since a successful CPI does not show that the intended economic operation occurred.
How should Solana token integrations be audited, including Token-2022?
Solana supports the original Token Program and Token-2022. Token-2022 adds extensions that can change how a mint or token account behaves, including transfer fees, transfer hooks, and permanent delegates. These features are documented in the Token Extensions reference.
Those differences matter when a protocol calculates balances or assumes that a transfer delivers the exact amount requested. If a deposit instruction transfers 100 tokens but a transfer fee means the vault receives less, crediting the depositor with 100 tokens can leave the accounting undercollateralized.
The same principle applies to authority. An audit should establish which program owns the mint and token accounts, which mint the accounts refer to, and who can mint, freeze, transfer, or burn the asset. Where Token-2022 extensions are supported, the review needs to account for their effects. Where they are not supported, the program should reject unsupported configurations rather than silently assume standard token behavior.
For bridge and vault systems, these checks are part of the accounting model. The protocol must track the amounts that actually moved, which can differ from the amounts an instruction requested.
What can go wrong with oracle integrations in Solana programs?
Oracle checks need to be consistent across the instructions that rely on prices. A protocol may validate price freshness during a deposit but omit the same check during a withdrawal or liquidation. It may also require fresh data without ensuring that the update process can run when the data becomes stale.
Certora's Lulo audit identified critical issues in withdrawal flows involving oracle freshness. One path lacked the expected stale-price check. Another required fresh data but did not update it first, causing withdrawals to fail once the data became stale. The report marks both findings as fixed.
These are different failure modes. Missing freshness validation can allow an operation to use outdated prices. An update flow that cannot recover from stale data can prevent users from withdrawing. An audit should trace how oracle data is updated, validated, and consumed across each relevant instruction, including what happens when an update fails.
How should accounting and rounding be verified in Solana protocols?
A protocol can validate accounts and permissions correctly and still lose funds through its accounting. Vaults, lending markets, staking systems, and exchanges all rely on relationships between assets, shares, prices, fees, and liabilities. Those relationships need to hold across deposits, withdrawals, liquidations, and other state transitions.
In its Kamino Vault review, Certora found a share-price manipulation issue involving the first depositor. Repeated deposits and withdrawals could push the share price high enough that small deposits minted zero shares, while slightly larger deposits could lose significant value to rounding. The review also identified a rounding issue in reserve withdrawals that could allow the reserve's total supply to be exceeded. The report records these findings as fixed.
Lulo had a different accounting problem involving referral fees. Referral shares were tracked across allocations in a way that could allow fees associated with one allocation to be claimed against another allocation with a more favorable exchange rate. That finding is also described in the Lulo report.
Both examples show why arithmetic should be reviewed in the context of the entire operation. A calculation can be locally correct while the surrounding state transitions allow an attacker to manipulate the exchange rate, claim value from the wrong allocation, or withdraw more than the protocol holds.
Manifest’s swap logic shows the same pattern in a trading setting. Its price-impact estimate counted global orders that no longer had funds behind them, so when execution removed those orders the swap could return less than the requested amount, or revert even though the user’s order could be filled. The report records the issue as fixed.
For a vault, the core properties are that share issuance and redemption use consistent accounting, rounding cannot create unbacked claims, and withdrawals cannot exceed available assets. For an exchange, the output recorded by the protocol must match what execution actually delivered. These properties should be checked across sequences of operations as well as against individual functions.
What should an audit check about account lifecycle and upgrades on Solana?
Solana separates program code from the accounts that hold application state. Programs can create and initialize accounts, close them, and, depending on the implementation, allow new accounts to be initialized later. These transitions need to preserve the protocol's assumptions about ownership and state.
In Certora's Fragmetric review, a fund manager could close a reward pool, and every later deposit and withdrawal then failed because the program still tried to update rewards on that pool and returned an error for closed pools. The report records the issue as fixed. An audit should trace what happens to related accounts and state when a pool, position, or configuration account is closed or reinitialized.
Program upgrades introduce another trust assumption. For upgradeable deployments, the upgrade authority can authorize new program code. That authority should be included in the protocol's security model, particularly where user assets are held or controlled by the program. Solana documents the process in its program deployment guide.
Which invariants matter for Solana protocols?
The invariants depend on the protocol, but they should describe its economic and authorization requirements across all relevant instructions. A user position must remain associated with the correct user and market. A vault must not transfer more assets than it holds, and no withdrawal may exceed what the withdrawing user is entitled to.Share issuance and redemption must preserve the intended exchange rate within defined rounding bounds. Oracle-dependent operations must enforce the required price and freshness checks. A swap must account for the amount actually exchanged.
For protocols using PDAs, the address and its stored state must represent the intended logical account. Token operations must use the expected mint, token program, and authority. Closing or reinitializing an account must not bypass restrictions or leave the remaining state inconsistent.
These properties should be checked across the instructions that can change the relevant state. If a property holds after a deposit but fails after a withdrawal or liquidation, the protocol does not preserve that invariant.
How should Solana programs be tested and verified?
Testing should cover more than successful transactions. It should include wrong or unrelated accounts, unauthorized signers, stale oracle data, failed CPIs, boundary values, and sequences of operations that change the state over time. For vaults and lending protocols, repeated deposits and withdrawals are especially useful for finding rounding and share-price issues. For trading systems, tests should cover partial execution and orders that cannot supply the requested amount.
Formal verification can provide stronger guarantees for properties that can be expressed precisely. Certora's reports on Kamino Vault and Manifest describe verification alongside manual review. The guarantees depend on the properties specified and the code included in the verification scope, so those boundaries need to be clear.
What should a team building on Solana prepare before an audit?
Before an audit, a team should document:
- the intended authorization model for each instruction
- the invariants the protocol must preserve
- the token programs and mints it supports, and how it handles unsupported ones
- the oracle update process, and what happens when an update fails
- who holds the program’s upgrade authority, and what that authority can do
These documents give the audit a baseline to check the code against.
Further reading
- Solana Core Documentation
- Program-Derived Addresses
- Cross-Program Invocations
- Anchor Account Constraints
- Token-2022 Extensions
- Certora Public Audit Reports
- Lulo Audit Report
- Manifest Audit Report
- Kamino Vault Audit Report
- Fragmetric Audit Report
Frequently asked questions
- What is a Solana smart contract audit? A review of a Solana program together with the accounts, authorities, program-derived addresses, token configurations and external programs it depends on. The audit checks that each instruction validates the accounts it receives and that the protocol’s accounting holds across sequences of operations.
- How does auditing Solana differ from auditing EVM contracts? EVM contracts keep their state in their own storage. Solana programs keep state in separate accounts that each transaction passes in, so every instruction must verify that the accounts it receives are the intended ones. Account ownership, signer privileges, program-derived addresses and cross-program invocations all affect which state a program can modify.
- Why does a valid signature not prove authorization? A signature shows that the signer controls a key. It does not show that the signer is entitled to act on the account supplied with the transaction. In Certora’s Lulo audit, deposit_pool required the owner’s signature but never checked that the signer matched the owner recorded in the UserAccount, which let an attacker become the referrer on other users’ accounts.
- Does Certora audit Solana programs? Yes. Certora has audited Solana protocols across lending, vaults, trading and restaking. Its public reports are on the Certora reports page.
