Missing Rent Check
Detects potential rent exemption issues from lamport transfers.
Missing Rent Check
Overview
Remediation Guide: How to Fix Missing Rent Check
The missing rent check detector identifies Solana programs that transfer variable amounts of lamports from accounts without verifying the remaining balance stays above the rent-exemption threshold. If too many lamports are withdrawn, the account may fall below rent exemption and be garbage-collected by the runtime, causing data loss.
Sigvex flags variable-amount TransferLamports operations where no balance comparison involving AccountLamports exists in the function. Full balance transfers (intentional closes) and constant-amount transfers are excluded.
Why This Is an Issue
- Account deletion: accounts below the rent-exempt minimum are eligible for garbage collection, permanently destroying their data.
- Denial of service: an attacker who can influence the transfer amount can drain an account to just below rent exemption, causing it to be deleted.
- Silent data loss: the account is deleted by the runtime asynchronously, not within the transaction, making the failure hard to debug.
CWE mapping: CWE-404 (Improper Resource Shutdown or Release).
How to Resolve
Native Solana
let rent = Rent::get()?;
let min_balance = rent.minimum_balance(account.data_len());
let remaining = account.lamports() - transfer_amount;
require!(remaining >= min_balance, ErrorCode::InsufficientRentBalance);
**account.try_borrow_mut_lamports()? -= transfer_amount;
**destination.try_borrow_mut_lamports()? += transfer_amount;
Anchor
// Anchor's system_program::transfer checks rent exemption
// For manual transfers, add a constraint:
#[account(mut, constraint = account.lamports() - amount >= Rent::get()?.minimum_balance(account.data_len()))]
pub account: Account<'info, MyState>,
Examples
Vulnerable
let amount = instruction_data.amount; // User-controlled
**account.try_borrow_mut_lamports()? -= amount;
**destination.try_borrow_mut_lamports()? += amount;
// No check if account stays rent-exempt
Fixed
let amount = instruction_data.amount;
let rent = Rent::get()?;
let min = rent.minimum_balance(account.data_len());
require!(account.lamports() - amount >= min, NotRentExempt);
**account.try_borrow_mut_lamports()? -= amount;
**destination.try_borrow_mut_lamports()? += amount;
JSON Finding
{
"detector": "missing-rent-check",
"severity": "Low",
"confidence": 0.65,
"title": "Variable Lamport Transfer May Break Rent Exemption",
"description": "Lamports transferred with variable amount without rent-exemption check.",
"cwe": [404]
}
Detection Methodology
The detector pre-scans the function for balance comparisons (expressions involving AccountLamports) and CPI calls. For each variable-amount TransferLamports, it generates a finding with confidence reduced if balance comparisons or CPI calls are present elsewhere in the function, as these suggest existing rent awareness.
Limitations
- Full-balance transfers are excluded since they indicate intentional account closure.
- Constant-amount transfers are excluded since the developer presumably knows the amount is safe.
- The detector cannot verify that a balance comparison actually checks rent exemption versus other conditions.
Related Detectors
- Rent Withdrawal Balance - detects partial withdrawals without balance checks.
- Rent Epoch Validation - detects improper rent epoch handling.