Skip to main content
Sigvex

Rent Exempt Reallocation

Detects account reallocations without rent-exemption lamport adjustments.

Rent Exempt Reallocation

Overview

Remediation Guide: How to Fix Rent Exempt Reallocation

The rent-exempt reallocation detector identifies account reallocations that do not properly adjust lamport balances to maintain rent exemption. When an account is resized, the rent-exemption requirement changes proportionally: growing requires additional lamports, and shrinking may leave excess lamports that should be returned. Failing to adjust can cause the runtime to garbage-collect the account.

Sigvex tracks realloc syscalls and checks whether corresponding lamport transfers, lamport reads, or rent sysvar accesses exist in the same function.

Why This Is an Issue

  • Garbage collection: growing an account without adding lamports leaves it below rent exemption, risking deletion.
  • Trapped funds: shrinking an account without returning excess lamports locks user funds in an over-funded account.
  • Silent failure: the account is deleted asynchronously, making the root cause difficult to trace.

CWE mapping: CWE-400 (Uncontrolled Resource Consumption).

How to Resolve

Native Solana

let rent = Rent::get()?;
let old_balance = account.lamports();
let required = rent.minimum_balance(new_size);

account.realloc(new_size, false)?;

if required > old_balance {
    let shortfall = required - old_balance;
    **payer.try_borrow_mut_lamports()? -= shortfall;
    **account.try_borrow_mut_lamports()? += shortfall;
} else if old_balance > required {
    let excess = old_balance - required;
    **account.try_borrow_mut_lamports()? -= excess;
    **destination.try_borrow_mut_lamports()? += excess;
}

Anchor

#[account(mut, realloc = new_size, realloc::payer = payer, realloc::zero = true)]
pub my_account: Account<'info, MyAccount>,

Examples

Vulnerable

account.realloc(new_size, false)?;
// No lamport adjustment — may lose rent exemption

Fixed

let rent = Rent::get()?;
let required = rent.minimum_balance(new_size);
account.realloc(new_size, true)?;
let shortfall = required.saturating_sub(account.lamports());
if shortfall > 0 {
    **payer.try_borrow_mut_lamports()? -= shortfall;
    **account.try_borrow_mut_lamports()? += shortfall;
}

JSON Finding

{
  "detector": "rent-exempt-reallocation",
  "severity": "High",
  "confidence": 0.75,
  "title": "Account Reallocation Without Rent-Exemption Adjustment",
  "description": "Account is reallocated without adjusting lamports for the new rent-exemption requirement.",
  "cwe": [400]
}

Detection Methodology

The detector identifies realloc syscalls and checks for lamport transfers, AccountLamports reads, or Rent sysvar access in the same function. If none of these indicators of rent awareness exist, a finding is generated for each realloc operation.

Limitations

  • Rent adjustments in helper functions or CPI calls are not tracked.
  • Anchor’s realloc constraint automatically handles rent but may not be distinguishable in decompiled code.
  • The detector flags all reallocations without rent handling, including shrinks where rent excess is acceptable.

References