Skip to main content
Sigvex

Readonly Misuse Remediation

How to fix readonly account misuse vulnerabilities.

Readonly Misuse Remediation

Overview

Detector Reference: Readonly Misuse

This guide explains how to fix patterns where accounts are written to without checking the is_writable flag.

Check is_writable before any write operation:

if !account.is_writable {
    return Err(ProgramError::InvalidAccountData);
}
let mut data = account.data.borrow_mut();
data[8..16].copy_from_slice(&new_value.to_le_bytes());

For Anchor, use #[account(mut)]:

#[account(mut)]
pub state: Account<'info, MyState>,

Alternative Mitigations

  1. Centralized validation: create a helper function that validates writability for all accounts at instruction entry.
  2. Const accounts pattern: use separate instruction definitions for read-only and read-write paths.
  3. an account-validation framework constraints: the account-validation framework’s #[account(mut)] attribute enforces writability at deserialization, preventing this class of bug.

Common Mistakes

  • Assuming all accounts are writable: callers control the is_writable flag. Never assume an account is writable without checking.
  • Checking after the write: the check must occur before the write to be effective.
  • Ignoring CPI propagation: writable flags propagate through CPI calls. If your program incorrectly marks accounts as writable, called programs may also write to them.

References