Skip to main content
Sigvex

Uninitialized Account Remediation

How to fix uninitialized account access vulnerabilities.

Uninitialized Account Remediation

Overview

Detector Reference: Uninitialized Account

This guide explains how to prevent reading from uninitialized accounts, which can lead to type confusion and attacker-controlled state injection.

Always check that an account is initialized before reading its data:

let account = &accounts[0];

// Check 1: Account has data
require!(!account.data_is_empty(), ProgramError::UninitializedAccount);

// Check 2: Discriminator is valid
let data = account.data.borrow();
require!(data[0..8] == EXPECTED_DISCRIMINATOR, ProgramError::InvalidAccountData);

// Check 3: Owner is correct
require!(*account.owner == program_id, ProgramError::IncorrectProgramId);

// Now safe to deserialize
let state = MyState::try_from_slice(&data[8..])?;

For Anchor, use typed Account<'info, T> which validates discriminator and owner automatically.

Alternative Mitigations

  1. Use data_is_empty(): a quick check that the account has been allocated.
  2. Owner check: uninitialized accounts are owned by the system program. Check account.owner == &program_id to confirm your program owns it.
  3. Anchor typed accounts: Account<'info, MyState> validates discriminator and owner at deserialization time.

Common Mistakes

  • Checking only data length: a non-empty account may still be uninitialized if created but never written to by your program. Always check the discriminator.
  • Using UncheckedAccount in Anchor: bypasses all automatic validation. Add manual checks if using UncheckedAccount.
  • Trusting init_if_needed: the account may have been pre-created by an attacker. Validate owner and discriminator even with init_if_needed.

References