Skip to main content
Sigvex

Rent Exempt Initialization

Detects account data writes before rent-exempt funding.

Rent Exempt Initialization

Overview

Remediation Guide: How to Fix Rent Exempt Initialization

The rent-exempt initialization detector identifies account initialization patterns where data is written before the account receives sufficient lamports for rent exemption. If an account is written to before being funded, the Solana runtime may purge it before the transaction completes, causing data loss and denial of service.

Sigvex tracks StoreAccountData events and TransferLamports events per account, reporting cases where the earliest data write precedes the earliest lamport transfer.

Why This Is an Issue

  • Account purging: the runtime may reclaim an unfunded account mid-transaction, destroying the data just written.
  • Data loss: initialization data is permanently lost if the account is garbage-collected before funding.
  • Denial of service: repeated failed initializations waste compute budget and user fees.

CWE mapping: CWE-665 (Improper Initialization).

How to Resolve

Native Solana

// CORRECT: Fund first, then write
let rent = Rent::get()?;
let required = rent.minimum_balance(account_size);

// Step 1: Fund the account
**payer.try_borrow_mut_lamports()? -= required;
**account.try_borrow_mut_lamports()? += required;

// Step 2: Write data (now safe)
let mut data = account.data.borrow_mut();
data[0..8].copy_from_slice(MY_DISCRIMINATOR);

Anchor

// SystemProgram::create_account atomically allocates, funds, and assigns
#[account(init, payer = user, space = 8 + 64)]
pub state: Account<'info, MyState>,

Examples

Vulnerable

// Write BEFORE funding — account may be purged
let mut data = account.data.borrow_mut();
data[0..8].copy_from_slice(MY_DISCRIMINATOR);

// Funding happens too late
**payer.try_borrow_mut_lamports()? -= required;
**account.try_borrow_mut_lamports()? += required;

Fixed

// Fund FIRST
**payer.try_borrow_mut_lamports()? -= required;
**account.try_borrow_mut_lamports()? += required;

// Then write
let mut data = account.data.borrow_mut();
data[0..8].copy_from_slice(MY_DISCRIMINATOR);

JSON Finding

{
  "detector": "rent-exempt-initialization",
  "severity": "High",
  "confidence": 0.65,
  "title": "Account Data Written Before Rent-Exempt Funding",
  "description": "Account has data written to it before receiving lamports for rent exemption.",
  "cwe": [665]
}

Detection Methodology

The detector collects two event types per account variable: data writes and lamport transfers. It compares the earliest write and earliest transfer using (block_idx, stmt_idx) ordering. If the write precedes the transfer, a finding is generated. CPI calls that may write to accounts are also tracked.

Limitations

  • The detector cannot track funding that occurs in a separate instruction within the same transaction.
  • SystemProgram::create_account atomically funds and allocates, but may not be distinguishable in decompiled bytecode.
  • Accounts that receive lamports from sources outside the current function are not tracked.

References