Vulnerabilities

Read-Only Reentrancy

Read-only reentrancy happens when a view function returns stale or inconsistent state during an unfinished state transition, and another contract relies on that value.

The view function does not change state, but it can still answer with the wrong value at the worst moment.

Read-Only Reentrancy Explained in Detail

Read-only reentrancy abuses a stale read, not a direct state write. The attacker triggers a state transition, enters a callback window, then calls a view function while accounting is only partly updated.

Another protocol, oracle integration, lending market, or vault may treat that stale value as valid.

Smart contract example

function removeLiquidity(uint256 shares) external {
    uint256 assetsOut = trackedAssets * shares / totalShares;

    totalShares -= shares;
    token.transfer(msg.sender, assetsOut); // callback window
    trackedAssets -= assetsOut;
}

function sharePrice() external view returns (uint256) {
    return trackedAssets * 1e18 / totalShares;
}

During the callback, totalShares is reduced but trackedAssets is not. A contract reading sharePrice() can see an inflated price.

Read-Only Reentrancy in Auditing

View functions often become oracle inputs. A stale view can move collateral values, LP token prices, vault exchange rates, rewards, or liquidation decisions.

The source protocol and the consuming protocol both need review.

Red flags in code

  • Views returning price, exchangeRate, getVirtualPrice, totalAssets, or pricePerShare.

  • External calls during withdraw, redeem, burn, swap, claim, or liquidity removal.

  • Integrations trusting same-block view values as oracle inputs.

  • Accounting split across multiple variables updated before and after a callback.

  • View functions that do not account for active transitions or locks.

  • Reentrancy guards used only on state-changing functions.

How to test or review it

  • Call oracle-like views from a receiver callback.

  • Compare view outputs before, during, and after the state transition.

  • Test consuming protocols that read the value in the same transaction.

  • Check whether views should revert during active state changes.

  • Prefer delayed, cached, or independently verified oracle values for protocol-critical pricing.

  • Add invariant tests for share price, total assets, reserves, and collateral values.

Sources