Solana and Rust program vulnerabilities in disclosed reports

Solana's account model moves the security burden from call ordering to account validation — the bugs look nothing like their EVM equivalents.

Reports indexed
34
Total paid
$600k
Critical
1
Largest payout
$600k

Solana programs are stateless code operating over accounts the caller supplies, which makes account validation the entire security boundary. The dominant bug class is a missing check: an account that is never verified as owned by the expected program, a signer flag never asserted, or a PDA derived without confirming the bump and seeds.

Type confusion is the second cluster. Two account structs with compatible layouts can be substituted for one another unless a discriminator is checked, which is precisely what Anchor's account discriminators exist to prevent — and precisely what raw programs and `AccountInfo` escape hatches skip.

Arithmetic differs too: Rust release builds wrap silently on overflow unless checked arithmetic is used explicitly, so the overflow class that Solidity 0.8 retired is still live here.

What reviewers look for

  • Accounts used without an owner check against the expected program
  • Missing `is_signer` assertions on authority accounts
  • PDA derivation without canonical bump verification
  • Type confusion between structurally similar account layouts
  • Unchecked arithmetic in release builds

Curated highlights

The largest disclosed payouts in this group, with our own summary of each. Every report links back to the original disclosure.

criticalAccess controlSolana-Rust$600k

Missing owner check on Solana instruction lets attacker drain vault

A missing program ownership check in a Solana yield vault protocol allowed unauthorized account spoofing during withdrawal processing. Because the instruction handler accepted an unchecked account and verified only a discriminator byte rather than validating account ownership, an attacker could supply a custom state account with manipulated fields. The protocol trusted the forged state data and generated a Program Derived Address (PDA) signature to execute a token transfer, enabling complete draining of the protocol's vault funds.

Solana Yield VaultimmunefiNov 3, 2022Open
mediumLogic errorSolana-Rust$0

Dango DEX: Any change in bucket size will DOS order cancellation leading to frozen user funds and halts the entire auction

Dango's auction-based DEX tracks liquidity depth per bucket, keyed by the bucket sizes configured when an order is created. When an administrator later updates pair bucket sizes via a batch update, order cancellation and auction cleanup both call decrease_liquidity_depths(), which reloads the new bucket sizes and fails because DEPTHS.modify() requires the old storage keys to still exist. Every cancellation attempt reverts, permanently freezing user funds, and the same failure in cron::auction() cleanup trips the protocol's pause mechanism, halting all trading and cutting off LP and protocol revenue.

Dango DEXsherlockSep 29, 2025Open
mediumAccess controlSolana-Rust$0

DODO Cross-Chain DEX: Bug in AccountEncoder causes wrong Solana account permissions

DODO's cross-chain bridge compresses Solana account permissions into a byte array in its EVM-side AccountEncoder library. The decompressAccounts() assembly routine reads a full 32-byte word with mload when parsing what should be a single 1-byte isWritable boolean, so the boolean evaluation consumes the boolean plus the first 31 bytes of the next account's public key. Because public keys are essentially always non-zero, every boolean collapses to true, marking all accounts writable regardless of user intent. This silently corrupts permission data for every multi-account Solana bridge transaction, expanding the attack surface where Solana programs may modify accounts users expected to be read-only. The finding was confirmed, rated medium (M-4), and fixed by extracting only the first byte via shr(248, ...).

DODO Cross-Chain DEXsherlockJun 9, 2025Open
highAccess controlSolana-Rust$0

DODO Cross-Chain DEX: Unauthorized Claim of Non-EVM Chain Refunds in `claimRefund` Function

DODO's omni-chain gateway contracts expose a claimRefund function that returns cross-chain refunds to their intended recipients. The authorization check determines the receiver by the stored walletAddress length: when the length is exactly 20 bytes (an EVM address) the caller must be that address, but for any other length the receiver simply becomes msg.sender, collapsing the guard into an always-true comparison. An attacker who watches for refund events carrying non-EVM addresses (e.g., Bitcoin) can front-run the legitimate claim and drain the contract of those funds at only gas cost. The supplied foundry test proves EVM refunds stay protected while a non-EVM refund is stolen, and the protocol addressed the flaw in a follow-up PR.

DODO Cross-Chain DEXsherlockJun 9, 2025Open
mediumLogic errorSolana-Rust$0

ZetaChain Cross-Chain: Solana zetaclient inbound observer is blocked indefinitely when an additional account is passed to the `call` instruction

The Solana gateway program's `call` instruction tolerates extra accounts in the instruction (it only needs one signer), but the Solana zetaclient's `ParseInboundAsCall` parser demands exactly one account via `len(instructionAccounts) != 1`. A single crafted transaction that appends an extra account executes successfully on-chain yet breaks parsing on the zetaclient observer, which re-scans the same failing signature every ticker and thereby stalls processing of all other inbound Solana transactions indefinitely. The protocol fixed the check to require at least one signer (`< 1`) in PR zeta-chain/node#3895.

ZetaChain Cross-ChainsherlockMay 12, 2025Open
highLogic errorSolana-Rust$0

ZetaChain Cross-Chain: Dirty EVM state changes are not committed before precompile calls, resulting in double-spending or loss of ZETA tokens

ZetaChain's EVM is implemented as ethermint on top of Cosmos SDK, and its staking precompiles execute Cosmos SDK logic (delegate, claim rewards) without first committing pending EVM statedb changes into the SDK state. SDK actions therefore read a stale balance, and when the EVM dirty state is committed at the end of the transaction it overwrites the SDK's freshly applied changes. This allows the same native ZETA to be transferred to another address in EVM and still delegated via the staking precompile (double spend), and in reward claims the freshly minted staking rewards are overwritten and lost. A complete e2e Go/Solidity PoC transfers a contract's full balance to 0xdead and then successfully stakes 2 ZETA to a validator, proving the double spend. The team acknowledged the issue but will not fix it at this time; the recommended mitigation (mirroring Evmos) is to flush EVM state before running SDK precompile code.

ZetaChain Cross-ChainsherlockMay 12, 2025Open

All reports in this group

Vulnerability classes seen on this chain

Related chain / vm pages