Anchor Constraint Ordering Remediation
How to fix incorrect Anchor constraint ordering.
Anchor Constraint Ordering Remediation
Overview
Related Detector: Anchor Constraint Ordering
Incorrect constraint ordering enables type confusion and privilege escalation. The fix is to rely on Anchor’s derive macro for automatic ordering, and when implementing manual checks, follow: discriminator, owner, signer, writable, custom.
Recommended Fix
Before (Vulnerable)
// Manual checks in wrong order
require!(user.is_signer, Unauthorized);
require!(user.owner == &program_id, InvalidOwner);
After (Fixed)
// Let Anchor handle ordering via derive macro
#[derive(Accounts)]
pub struct MyInstruction<'info> {
#[account(owner = my_program::ID)] // Owner checked first
pub data: Account<'info, MyData>, // Discriminator auto-checked
pub user: Signer<'info>, // Signer checked by type
}
Alternative Mitigations
For native programs, enforce the correct manual order explicitly:
// 1. Discriminator
require!(account.data.borrow()[..8] == MyData::DISCRIMINATOR, InvalidDiscriminator);
// 2. Owner
require!(account.owner == program_id, InvalidOwner);
// 3. Signer
require!(account.is_signer, MissingSignature);
// 4. Writable
require!(account.is_writable, AccountNotWritable);
// 5. Custom constraints
require!(data.authority == authority.key(), Unauthorized);
Common Mistakes
Mistake: Relying on Anchor but Adding Manual Checks in Wrong Order
// WRONG: Anchor checks discriminator and owner, but manual check order is wrong
pub fn handler(ctx: Context<MyCtx>) -> Result<()> {
require!(ctx.accounts.data.amount > 0, ZeroAmount); // Custom before signer
require!(ctx.accounts.user.is_signer, Unauthorized); // Redundant and wrong order
Trust Anchor’s constraint system and avoid redundant manual checks.