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.
Recommended Fix
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
- Centralized validation: create a helper function that validates writability for all accounts at instruction entry.
- Const accounts pattern: use separate instruction definitions for read-only and read-write paths.
- Anchor constraints: Anchor’s
#[account(mut)]attribute enforces writability at deserialization, preventing this class of bug.
Common Mistakes
- Assuming all accounts are writable: callers control the
is_writableflag. 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.