Free 30-min Web3 Consultation
Book Now
Smart Contract Security Audits
Learn More
Custom DeFi Protocol Development
Explore
Full-Stack Web3 dApp Development
View Services
Free 30-min Web3 Consultation
Book Now
Smart Contract Security Audits
Learn More
Custom DeFi Protocol Development
Explore
Full-Stack Web3 dApp Development
View Services
Free 30-min Web3 Consultation
Book Now
Smart Contract Security Audits
Learn More
Custom DeFi Protocol Development
Explore
Full-Stack Web3 dApp Development
View Services
Free 30-min Web3 Consultation
Book Now
Smart Contract Security Audits
Learn More
Custom DeFi Protocol Development
Explore
Full-Stack Web3 dApp Development
View Services
LABS
Glossary

Read-Only Reentrancy

A smart contract vulnerability where a state-dependent view function is called during a state-changing transaction, returning inconsistent data to an external caller.
Chainscore © 2026
definition
BLOCKCHAIN SECURITY VULNERABILITY

What is Read-Only Reentrancy?

A sophisticated smart contract vulnerability where a read-only or view function makes an external call that triggers a state-modifying reentrant callback, corrupting the caller's internal state assumptions.

Read-only reentrancy is a smart contract vulnerability where a view or pure function, which is designed to only read state without modifying it, makes an external call to another contract. This external call can re-enter the original contract through a callback function that does modify state, leading to inconsistent or corrupted data being returned by the initial read-only function. Unlike classic reentrancy, the attack vector originates from a function assumed to be safe, making it harder to detect with standard security patterns like the Checks-Effects-Interactions pattern, which only guards state-changing functions.

The core mechanism exploits the gap between a contract's internal accounting state and its external, dependent state. A common scenario involves a liquidity pool contract. An attacker might call a pool's getReserves() view function, which internally calls a token contract's balanceOf() to calculate the price. If the token's callback allows reentrancy into the pool to perform a swap or withdrawal before the view function completes, the price calculation will use manipulated, post-withdrawal balances, enabling exploits like oracle manipulation or flash loan attacks. This creates a temporal inconsistency between the read data and the true on-chain state.

Mitigating read-only reentrancy requires defensive programming techniques beyond standard reentrancy guards. Key strategies include using state mutex locks (reentrancy guards) on view functions, employing pull-over-push patterns for external calls, and carefully auditing any external interactions within view functions. Developers must treat view functions that perform external calls with the same caution as state-changing functions. Formal verification tools and security audits are increasingly focusing on this vulnerability, as it was a critical factor in several major DeFi exploits, including the 2022 attack on the Fantom-based Multichain bridge.

how-it-works
SECURITY VULNERABILITY

How Read-Only Reentrancy Works

Read-only reentrancy is a sophisticated smart contract vulnerability where an external call manipulates an internal state view without triggering standard reentrancy guards, exploiting the discrepancy between a contract's actual state and its perceived state by other protocols.

Read-only reentrancy is a smart contract exploit that occurs when a function makes an external call to a malicious contract, which then calls back into the original protocol or, more critically, into a separate, dependent protocol in a read-only manner (e.g., via a view or staticcall). Unlike classic reentrancy, the attacker's callback does not directly modify the vulnerable contract's state during the lock; instead, it manipulates the perception of that state. The core vulnerability arises because the victim contract's internal accounting (its true state) is temporarily inconsistent during its execution, but dependent protocols querying it see outdated or incorrect data via their view functions.

The attack typically unfolds in a multi-contract DeFi ecosystem. For example, a lending protocol A might be in a mid-operation state where a user's collateral is marked for withdrawal but not yet transferred. If a malicious contract calls into A to trigger this state, and then—during the same transaction—calls lending protocol B which relies on A's price oracle, B might read A's inconsistent state (e.g., inflated liquidity or incorrect collateral ratios) to borrow funds or mint assets it shouldn't be entitled to. The key is that B's call is a read-only query, bypassing any reentrancy locks A has on state-changing functions.

This vulnerability is particularly insidious because it evades traditional guards. Standard reentrancy protection like the Checks-Effects-Interactions pattern or OpenZeppelin's ReentrancyGuard only prevent reentrant calls that modify the guarding contract's own state. They do not protect against external protocols making read-only calls to query the contract's mid-transaction state. The flaw is therefore in the compositional assumptions between protocols; each contract may be individually secure, but their interaction creates a dangerous oracle failure.

To mitigate read-only reentrancy, developers must adopt a composition-aware security model. Critical view functions that expose protocol state to external integrators should be designed to resist manipulation. Techniques include using state checks that revert if the contract itself is in an unsafe, mid-operation state (e.g., a "lock" variable readable by view functions), or employing pull-based payment patterns where final state updates occur before any external calls. Auditing must consider not just a contract in isolation, but its role as a data oracle within the broader DeFi landscape.

key-features
READ-ONLY REENTRANCY

Key Characteristics

Read-only reentrancy is a sophisticated vulnerability where a contract's state appears consistent during an external call, but its internal view functions return outdated or manipulated data, allowing an attacker to exploit the discrepancy.

01

State Inconsistency During Call

The core mechanism involves a contract making an external call to an attacker's contract while its own state is in a temporary, inconsistent state (e.g., balances not yet updated). Standard reentrancy guards protect state-modifying functions, but view functions remain callable and return data based on this inconsistent state.

02

Exploitation via View Functions

Attackers exploit this by having the called contract re-enter the vulnerable protocol through its read-only or view functions. For example, an attacker might call a pricing oracle (getPrice()) or liquidity check (getReserves()) that calculates values using outdated internal balances, leading to incorrect valuations and illegitimate trades or withdrawals.

03

The Checks-Effects-Interactions Pattern

This classic security pattern is insufficient to prevent read-only reentrancy. While it prevents state changes during reentrancy (Effects before Interactions), it does not protect view functions that are called after the external interaction but before the state is finalized. The vulnerability exists in the logical state exposed to view functions.

04

Common Attack Vectors

  • Lending Protocols: Borrowing based on outdated collateral prices from an oracle.
  • Automated Market Makers (AMMs): Withdrawing liquidity or swapping tokens using manipulated pool reserve data.
  • Yield Aggregators: Incorrectly calculating share prices or rewards during a deposit/withdrawal cycle.
05

Mitigation: State Consistency Locks

Effective mitigation requires ensuring logical state consistency during external calls. Techniques include:

  • Using a reentrancy guard on view functions (e.g., OpenZeppelin's ReentrancyGuard on functions with the nonReentrant modifier, even if they are view).
  • Implementing mutex locks that block critical view functions during state transitions.
  • Designing systems where price oracles fetch data after all state updates are complete.
06

Real-World Example: 2022 Lodestar Finance Exploit

A prominent example occurred on the Platypus Finance protocol, exploited via Lodestar Finance. The attacker used a read-only reentrancy in the deposit() function to manipulate the exchange rate between USDC and the protocol's lpToken. By re-entering through a view function that calculated the exchange rate based on outdated reserves, the attacker artificially inflated their collateral value and drained funds.

real-world-examples
CASE STUDIES

Real-World Examples & Exploits

Read-only reentrancy is a subtle vulnerability where a protocol's internal state appears consistent during a call, but dependent external protocols see outdated data. These examples illustrate how attackers exploit this state discrepancy.

02

Mechanism: State Discrepancy

The core vulnerability is a temporary inconsistency between a contract's internal accounting and its external view. Key phases:

  • Phase 1: An update function (e.g., transferring tokens) begins but hasn't written the new state.
  • Phase 2: A view function (e.g., balanceOf) is called reentrantly. It returns the old, pre-update state.
  • Phase 3: An external protocol relying on this outdated data makes an incorrect decision, such as approving an undercollateralized loan.
04

Prevention: The Checks-Effects-Interactions Pattern

The primary defense is strict adherence to the CEI pattern:

  1. Checks: Validate all conditions (e.g., sufficient balance).
  2. Effects: Update all internal state variables first (e.g., deduct balances).
  3. Interactions: Make external calls last (e.g., transfer tokens). By finalizing state before any external interaction, you eliminate the window where view functions can return stale data. This must be combined with reentrancy guards on state-changing functions.
05

Detection & Tooling

Identifying read-only reentrancy requires specialized analysis because it spans multiple contracts. Key tools and methods include:

  • Static Analyzers: Slither and MythX can detect potential state inconsistencies after external calls.
  • Formal Verification: Tools like Certora can prove that a contract's state is consistent at all external view entry points.
  • Fuzzing & Invariant Testing: Frameworks like Foundry can test that certain invariants (e.g., total collateral >= total debt) hold even during reentrant calls.
06

Related Vulnerability: Price Oracle Manipulation

Read-only reentrancy often targets price oracles or liquidity checks. A common attack vector:

  • Manipulate a DEX pool's spot price via a large, reentrant swap during a state update.
  • A lending protocol's oracle (e.g., using getReserves()) reads the manipulated price.
  • The attacker borrows assets at an incorrect exchange rate. This differs from flash loan oracle attacks as it exploits the timing of the state read, not just capital size.
security-considerations
READ-ONLY REENTRANCY

Security Considerations & Impact

Read-only reentrancy is a novel smart contract vulnerability where an attacker manipulates a contract's internal state by making a reentrant call to a function that is incorrectly assumed to be state-pure, exploiting the discrepancy between the contract's actual state and the view presented to external callers.

01

Core Vulnerability

The attack exploits the gap between a contract's actual internal state and the view of that state presented to external, non-state-modifying (view) functions. An attacker reenters a view function during a state-changing operation, causing it to return data based on an inconsistent, mid-update state.

  • Example: A lending protocol's getAccountLiquidity() function might read a user's collateral balance from a vault that is currently being withdrawn, incorrectly reporting high liquidity and allowing unsafe borrowing.
02

The Reentrancy Lock Bypass

Standard reentrancy guards (e.g., nonReentrant modifiers) protect functions that modify state, but they do not lock view or pure functions. An attacker can call these "read-only" functions during a callback, effectively bypassing the intended protection.

  • Mechanism: 1) Attacker triggers a state-changing function (e.g., withdraw). 2) During its execution, a callback is made to the attacker's contract. 3) The attacker's contract reenters the vulnerable protocol via a view function, which reads corrupted state. 4) Based on this false data, the attacker executes a harmful action in a separate, connected system.
03

Cross-Contract Impact

The primary danger is cross-contract manipulation. The corrupted read is often used by an external, integrated protocol (e.g., a DEX, oracle, or another lending market) to make a critical decision.

  • Real-World Vector: The attacker corrupts the reported price of an LP token in Vault A. A separate lending protocol, TrustedProtocol B, uses this price to determine collateral value. TrustedProtocol B, seeing inflated collateral, permits an oversized, undercollateralized loan to the attacker.
04

Prevention: CEI & State Consistency

The fundamental defense is adhering to Checks-Effects-Interactions (CEI) and ensuring state consistency before any external call. Specific mitigations include:

  • Internal State Consistency: Complete all state updates (Effects) before making external calls (Interactions).
  • Reentrancy Guards on View Functions: Apply guards to sensitive view functions that are called by external integrators, treating them as potentially stateful.
  • Using Private/Internal Functions: For sensitive state reads called during state changes, use private or internal visibility to prevent external reentry.
05

Detection & Analysis

Identifying read-only reentrancy requires static analysis and careful review of cross-contract dependencies.

  • Static Analysis Tools: Advanced tools like Slither and MythX can detect patterns where view functions are called after external calls.
  • Code Review Focus: Auditors must trace all view functions used by external protocols, especially those reading balances, prices, or liquidity metrics. Any state change that makes an external call before finalizing its own state is a potential vector.
06

Historical Context & Impact

The vulnerability was formally identified and named in a 2022 research post by ChainSecurity. It represents an evolution of classical reentrancy, exploiting the composable nature of DeFi.

  • Notable Incidents: While no single massive exploit is solely attributed to it, the pattern has been identified in several high-value protocols during audits, leading to critical fixes. It underscores the security risks inherent in DeFi composability, where the security of one protocol depends on the state integrity of another.
VULNERABILITY COMPARISON

Read-Only vs. Classic Reentrancy

A comparison of two distinct smart contract attack vectors that exploit the reentrancy pattern.

FeatureClassic ReentrancyRead-Only Reentrancy

Primary Attack Vector

State-changing external call

State-reading external call (view function)

State Mutability During Call

Contract state is inconsistent (mid-update)

Contract state is consistent but stale/cached

Typical Guard Bypass

Checks-Effects-Interactions pattern not followed

Reliance on stale on-chain data (e.g., DEX price oracles)

State Variable Protection

Reentrancy guard locks (e.g., nonReentrant)

Ineffective; does not prevent view calls

Common Target

Functions updating balances (withdraw, transfer)

Functions relying on external price/data (liquidity checks, swaps)

Example

TheDAO attack (2016)

Uniswap V2 TWAP oracle manipulation

Mitigation Strategy

Checks-Effects-Interactions, reentrancy guards

Using internal, time-weighted price accumulators, circuit breakers

prevention-mitigation
READ-ONLY REENTRANCY

Prevention & Mitigation Strategies

Read-only reentrancy exploits state inconsistencies during a call to a view function. These strategies focus on preventing invalid state assumptions and securing cross-contract interactions.

01

The Checks-Effects-Interactions Pattern

The foundational defense against all reentrancy. It mandates a strict execution order:

  • Checks: Validate all conditions and inputs.
  • Effects: Update the contract's internal state before any external calls.
  • Interactions: Perform external calls last. This ensures the contract's state is finalized and consistent before reentrancy is possible, making read-only reentrancy attempts see the correct, updated state.
02

State-Consistent View Functions

Design view/pure functions to be resilient to intermediate state. Key techniques include:

  • Using a single SLOAD for a state variable and storing it in a local memory variable for calculations.
  • Avoiding logic that performs comparisons between two separate state reads that could be inconsistent mid-transaction.
  • Documenting that view functions may return transient, in-progress states during a transaction's execution.
03

Reentrancy Guards on State-Mutating Functions

Applying a non-reentrant modifier (like OpenZeppelin's ReentrancyGuard) to any function that makes an external call. While primarily for classic reentrancy, it also prevents the interleaving of transactions that create the inconsistent state read-only attacks depend on. This is a critical mitigation for functions that update shared state later read by view functions.

04

Synchronization Primitives & Mutexes

Implement low-level locking mechanisms for critical shared resources. This can involve:

  • A locked state variable that must be checked before accessing a sensitive vault or oracle.
  • Ensuring that any function reading a dependent value also checks the lock status of its source. This explicitly serializes access, preventing the race condition where a view function reads a partially updated dependency.
05

Architectural Isolation

Decouple systems to minimize trust assumptions. Strategies include:

  • Using internal balances (like ERC-4626 shares) instead of direct asset queries for calculations.
  • Designing oracles and price feeds to be self-contained and not reliant on the state of other potentially reentrant protocols.
  • Treating external view calls as untrusted inputs and sanitizing or validating them when used.
READ-ONLY REENTRANCY

Common Misconceptions

Read-only reentrancy is a sophisticated smart contract vulnerability where a malicious contract manipulates the state of a victim contract during a read-only call, exploiting the gap between a contract's internal state and its external view of other contracts. This section clarifies its mechanisms and dispels common misunderstandings.

Read-only reentrancy is a smart contract vulnerability where an attacker exploits a state inconsistency during a view function call to manipulate a victim contract's logic. It works by having a malicious contract, during its own execution (e.g., in a receive() or fallback() function), make a read-only call to a victim contract. The victim's view function reads state from a third-party protocol that the attacker is simultaneously manipulating via reentrancy, causing the victim to base its logic on stale or incorrect data. Unlike classic reentrancy, no state is written in the victim during the initial call, bypassing common reentrancy guards.

Key Mechanism: The attack creates a temporary fork in the perceived state. While Contract A executes, it queries Contract B's state. The attacker re-enters Contract B from within Contract A's callback, changing B's state before A's query resolves, but A's logic uses the pre-manipulation value.

READ-ONLY REENTRANCY

Frequently Asked Questions

Read-only reentrancy is a sophisticated smart contract vulnerability where a function's state is manipulated during a callback, even if the function itself is non-reentrant. These questions address its mechanisms, risks, and prevention.

Read-only reentrancy is a smart contract vulnerability where an attacker exploits a callback to a view function to manipulate the perceived state of a protocol, even when the primary state-changing function is protected by a standard reentrancy guard. It works by re-entering a contract not through a state-modifying function, but through an external call to a view or pure function that reads from a corrupted or intermediate state. For example, during a complex transaction, a protocol might query a lending pool's getAccountLiquidity() function. If this read is made while the pool's internal accounting is temporarily inconsistent (e.g., during a flash loan or another user's withdrawal), the query returns incorrect data, allowing the attacker to pass liquidity checks and perform unauthorized actions. This attack famously bypassed the non-reentrant modifier in the 2022 Nomad Bridge hack.

further-reading
READ-ONLY REENTRANCY

Further Reading & Resources

Deepen your understanding of this subtle vulnerability with technical papers, real-world incidents, and security best practices.

02

Real-World Exploit: Lido & Aave

In July 2022, a read-only reentrancy vulnerability was exploited, allowing an attacker to manipulate Aave's health factor calculation by re-entering via Lido's stETH rebasing mechanism.

  • Mechanism: The attacker used a flash loan and a malicious contract to call stETH during an Aave liquidation, tricking Aave into seeing an incorrect, inflated collateral balance.
  • Outcome: The vulnerability was white-hat reported and fixed before significant funds were lost, but it demonstrated the critical, cross-protocol nature of the threat.
03

Detection & Prevention Guide

Preventing read-only reentrancy requires moving beyond simple nonReentrant modifiers.

  • Best Practices:
    • Checks-Effects-Interactions (CEI): Strictly enforce this pattern, even for view/pure functions called externally.
    • State Consistency Checks: Add internal guards that revert if critical invariants are violated mid-transaction.
    • Static Analysis: Use tools like Slither or Scribble to detect potential state inconsistencies after external calls.
04

Technical Deep Dive: Balancer Vulnerability

A classic example where the Balancer Vault was vulnerable. The joinPool and exitPool functions performed an external callback to the caller before updating the Vault's internal token balances.

  • The Flaw: A malicious pool contract could re-enter the Vault during this callback. A subsequent getPoolTokens call would return stale, pre-update balances, enabling price manipulation.
  • The Fix: Balancer moved the callback to after all internal state updates, restoring the CEI pattern.
05

Security Tooling & Audits

Specialized tools are essential for finding these complex vulnerabilities.

  • Slither: A static analysis framework that can detect read-only reentrancy by identifying functions that perform external calls while a contract is in an inconsistent state.
  • Fuzzing & Formal Verification: Tools like Echidna or Certora Prover can be used to formally specify and test that critical state invariants hold across all execution paths, including reentrant ones.
ENQUIRY

Get In Touch
today.

Our experts will offer a free quote and a 30min call to discuss your project.

NDA Protected
24h Response
Directly to Engineering Team
10+
Protocols Shipped
$20M+
TVL Overall
NDA Protected direct pipeline
Read-Only Reentrancy: Definition & Security Impact | ChainScore Glossary