On EVM chains, chain ID mismatch is at least detectable in principle. A wallet that sends eth_chainId to its configured RPC gets back a single integer that it can compare against an expected value. The defense surface is narrow but real. Solana's architecture removes even that anchor point. There is no chain ID equivalent that a Solana RPC can return to confirm it's serving the network you expect. The question of whether an RPC endpoint is legitimate collapses entirely into whether you trust the operator — and that trust is often implicit, unexamined, and exploitable.
Solana RPC poisoning is not primarily a network-level attack. It operates at the layer between your wallet software and the endpoint it queries: account state, recent blockhash, and transaction simulation. Getting any of those wrong silently can redirect a signed transaction to an outcome the user never intended.
How Solana's RPC model creates the attack surface
When you initiate a transaction on Solana, your wallet or client library does several things before presenting the transaction for signing. It fetches a recent blockhash from the RPC (required for transaction validity — transactions without a recent blockhash are rejected by the network). It typically calls getAccountInfo on the program and relevant accounts to populate the instruction data. It may call simulateTransaction to verify the transaction won't fail before spending the signing step.
A malicious RPC endpoint can intervene at any of these steps. The most damaging attack vector is account substitution: when the client calls getAccountInfo for a token account or program account, the endpoint returns a different account's data — for example, a token account owned by an attacker-controlled address instead of the user's address. The wallet constructs the transaction with this substituted account data. The user signs what looks like a legitimate transfer instruction. The transaction, when submitted to the actual network, routes to the attacker's account.
The subtlety here is that Solana transactions are account-list explicit. Every account that an instruction touches must be enumerated in the transaction. A wallet that populates this account list from RPC responses is trusting that the RPC is returning accurate account pubkeys. If it isn't, the signed transaction carries the wrong accounts — and once signed, the user's signature authorizes exactly what's in the transaction, regardless of what they thought they were approving.
Stale slot responses and what they enable
Beyond account substitution, slot staleness is a quieter attack vector that enables a different class of manipulation. Solana's recent blockhash mechanism requires that a transaction include a blockhash from within the last ~150 slots (approximately 60 seconds under normal conditions). Stale RPCs that are far behind the current slot may serve old blockhashes that are technically still valid but close to expiry. This creates a window where a transaction submitted from a lagging RPC might fail with BlockhashNotFound on the actual network — not because the transaction is malformed, but because the RPC's view of "recent" doesn't match the network's current state.
More consequentially, a stale RPC's account state may be many slots behind. If the attacker controls the endpoint and the user is querying it to check their own token balance before sending, the balance shown may not reflect recent transactions. This can be used to manipulate the perceived state of an account — for instance, making a compromised or drained account appear to still hold funds, prompting the user to initiate transactions they would not otherwise make.
The Anchor IDL drift problem
Solana programs built with Anchor — the dominant framework for on-chain program development — expose their interface through an IDL (Interface Definition Language) file, typically fetched from on-chain storage or a hosted endpoint. The IDL describes instruction names, account layouts, and argument types. Client-side libraries use it to construct and decode transactions.
IDL drift is the condition where the deployed program and the IDL a client has cached or fetched are out of sync. Program upgrades on Solana can change instruction layouts without updating the IDL immediately, or vice versa. A poisoned RPC endpoint can serve a modified IDL — one that redefines an account slot's role or an argument's offset — causing the client library to construct malformed instructions that move funds to unexpected destinations.
Consider an active trading operation on a Solana-based DEX aggregator. The client fetches the program's IDL from the configured RPC endpoint to decode swap instructions. A poisoned endpoint serves an IDL where the destination account position in the swap instruction is offset by one slot. The constructed transaction has the correct instruction discriminator, passes simulation on the poisoned endpoint, but when executed on the real network it routes the swap output to the wrong recipient account. The trader sees a successful transaction; the funds land somewhere they didn't intend.
We're not saying IDL drift is always an attack — program upgrades that temporarily desync the IDL are a genuine operational issue on Solana. But a poisoned RPC that intentionally serves a mismatched IDL is indistinguishable from an accidental drift from the client's perspective. The client has no way to verify IDL integrity without comparing against an independent source.
Detection approaches that actually work
The naive mitigation — "only use trusted RPCs" — misses the point. The threat model includes endpoints that were trusted when configured and became compromised later, or endpoints that fail intermittently in ways that produce incorrect responses without fully going offline.
The effective approach is cross-verification at the RPC layer before transaction construction. For account state queries, this means querying two independent endpoints and comparing the responses. Divergence is a hard stop — not a warning to dismiss. For IDL fetches, this means comparing the IDL hash against a pinned version in the client configuration or against an on-chain account that holds the canonical IDL hash. An IDL that hashes differently from what the client expects should not be used to construct transactions.
For blockhash freshness, the check is straightforward: the slot of the returned blockhash should be within a known range of the current network slot. An endpoint serving a blockhash from 200 slots ago is either severely lagging or lying. Either way, it should not be used for transaction construction in that state.
Solana's transaction structure also provides a partial defense: the user's hardware wallet signs a serialized transaction that includes the full account list. If the signing software surfaces the full list of account pubkeys before the signing prompt — rather than just the instruction name — the user can verify that the accounts match their expected counterparties. This is not how most current wallet UIs work, but it is the information that's available in the transaction before signing.
Why this is harder to detect than EVM chain ID mismatch
EVM chain ID mismatch fails loudly in some cases — a transaction signed for Base will not land on Arbitrum because the chain ID in the signature doesn't match. The outcome is a failed transaction with a clear signal. Solana RPC poisoning typically doesn't fail loudly. The transaction succeeds on the actual network — it just moves funds to an account that wasn't the user's intent. There's no "wrong network" error. There's a successful signature on a transaction that did what the attacker wanted it to do, not what the user thought they were approving.
That asymmetry — silent success on the attacker's terms — is what makes Solana RPC poisoning a more operationally dangerous vector than its EVM equivalents. The time between signing and discovering the damage is longer, and the on-chain evidence is harder to distinguish from legitimate activity. The only reliable mitigation is verification before signing, not reconstruction after.