Anchor Constraint TOCTOU
Detects Time-of-Check-Time-of-Use vulnerabilities in Anchor constraint validation.
Anchor Constraint TOCTOU
Overview
The Anchor constraint TOCTOU detector identifies Time-of-Check-Time-of-Use vulnerabilities where account constraints read account data before a CPI call that may modify that same account. If the CPI changes the account data, the original constraint check becomes invalid, creating a race condition.
For remediation guidance, see Anchor Constraint TOCTOU Remediation.
Why This Is an Issue
In Anchor programs, account constraints are checked sequentially. If a constraint reads an account’s balance or state, and a subsequent CPI modifies that same account, the original check no longer reflects reality. An attacker can craft CPI calls that invalidate prior checks, leading to authorization bypass, state manipulation, and constraint bypass.
How to Resolve
Before (Vulnerable)
// Vulnerable: balance checked before CPI that modifies it
pub fn process(ctx: Context<Process>) -> Result<()> {
let balance = ctx.accounts.user_token.amount;
require!(balance >= MIN_BALANCE, InsufficientBalance);
// CPI modifies user_token balance -- original check is stale
token::transfer(ctx.accounts.into_transfer_ctx(), balance)?;
// balance variable is now stale
Ok(())
}
After (Fixed)
// Fixed: perform CPI first, then validate post-state
pub fn process(ctx: Context<Process>) -> Result<()> {
let amount = ctx.accounts.user_token.amount;
token::transfer(ctx.accounts.into_transfer_ctx(), amount)?;
// Reload account data after CPI
ctx.accounts.user_token.reload()?;
require!(ctx.accounts.user_token.amount == 0, TransferIncomplete);
Ok(())
}
Example JSON Finding
{
"detector": "anchor-constraint-toctou",
"severity": "high",
"confidence": 0.7,
"message": "Account state read before CPI that modifies the same account -- TOCTOU race",
"location": { "function": "process", "block": 0, "statement": 3 }
}
Detection Methodology
- State read tracking: Identifies account data reads and the variables they populate.
- CPI detection: Locates CPI calls that reference accounts from which state was previously read.
- Stale usage detection: Flags usage of pre-CPI variable values after the CPI executes.
- Account overlap analysis: Determines which CPI calls could modify which accounts.
Limitations
False positives: CPI calls to programs that do not modify the checked account data may be flagged. False negatives: Complex state dependencies through multiple intermediary accounts may not be traced.
Related Detectors
- Anchor Constraint Ordering — constraint order issues
- Cross-Program State — state inconsistencies across CPI