Skip to main content
Sigvex

Read-Only Reentrancy

Detects potential read-only reentrancy through CPI calls where a callee reads stale state from the caller during a callback.

Read-Only Reentrancy

Overview

The read-only reentrancy detector identifies CPI patterns where a Solana program invokes another program that may call back and read the invoking program’s account data before state updates are complete. Unlike write reentrancy (where the attacker modifies state), read-only reentrancy exploits stale read values — a callee reads a pool’s reserves or total supply mid-update and uses the stale values for pricing.

Why This Is an Issue

In Solana, CPI calls execute synchronously. If Program A updates reserves in two steps (update reserve0, invoke Program B, then update reserve1), Program B sees an inconsistent state where reserve0 is updated but reserve1 is not. If Program B calculates prices from these reserves, it gets an incorrect result. This enables the attacker to trade at a favorable price or extract value from the pool.

How to Resolve

// Before: Vulnerable — CPI between state updates
pub fn swap(ctx: Context<Swap>, amount: u64) -> Result<()> {
    ctx.accounts.reserve_a.amount -= amount;  // Update first reserve
    // CPI — callee sees inconsistent reserves
    invoke(&oracle_update_ix, &ctx.accounts.to_account_infos())?;
    ctx.accounts.reserve_b.amount += output;  // Update second reserve
    Ok(())
}

// After: Fixed — complete all state updates before CPI
pub fn swap(ctx: Context<Swap>, amount: u64) -> Result<()> {
    ctx.accounts.reserve_a.amount -= amount;
    ctx.accounts.reserve_b.amount += output;
    // All state is consistent before any CPI
    invoke(&oracle_update_ix, &ctx.accounts.to_account_infos())?;
    Ok(())
}

Detection Methodology

  1. CPI identification: Locates invoke and invoke_signed calls within function bodies.
  2. State update ordering: Tracks StoreAccountData operations relative to CPI calls.
  3. Stale read detection: Identifies cases where account data is modified before CPI but related data is modified after, creating an inconsistent window.
  4. Read-path analysis: Checks if the CPI target could read the partially-updated accounts.

Limitations

False positives: Programs that intentionally perform CPI between independent state updates may be flagged. False negatives: Indirect read-only reentrancy through multi-hop CPI chains may not be detected.

References