Skip to main content
Sigvex

Anchor Upgrade Security

Detects unsafe Anchor program upgrade patterns and missing security controls.

Anchor Upgrade Security

Overview

The Anchor upgrade security detector identifies unsafe program upgrade patterns including upgrade authority not validated before upgrades, no upgrade delay mechanism (timelock), missing upgrade proposal validation, direct BPFLoader upgrade calls without safeguards, and missing multi-signature requirements.

For remediation guidance, see Anchor Upgrade Security Remediation.

Why This Is an Issue

A compromised upgrade authority can replace the entire program with malicious code, stealing all funds controlled by the program. Anchor programs are upgradeable by default, and without multi-sig governance and timelock delays, a single compromised key is sufficient for a total protocol takeover. This has occurred in real-world incidents where upgrade authorities were stored in hot wallets.

How to Resolve

Before (Vulnerable)

// Vulnerable: single authority, no timelock, no multi-sig
pub fn upgrade(ctx: Context<Upgrade>) -> Result<()> {
    invoke(
        &bpf_loader_upgradeable::upgrade(
            ctx.accounts.program.key,
            ctx.accounts.buffer.key,
            ctx.accounts.authority.key,
            ctx.accounts.spill.key,
        ),
        &ctx.accounts.to_account_infos(),
    )?;
    Ok(())
}

After (Fixed)

// Fixed: multi-sig authority with mandatory timelock
pub fn upgrade(ctx: Context<Upgrade>) -> Result<()> {
    let config = &ctx.accounts.config;
    // Verify multi-sig threshold met
    require!(
        ctx.accounts.multisig.threshold_met(),
        ErrorCode::InsufficientSignatures
    );
    // Verify timelock expired
    let clock = Clock::get()?;
    require!(
        clock.unix_timestamp >= config.upgrade_proposed_at + TIMELOCK_SECONDS,
        ErrorCode::TimelockPending
    );
    invoke(
        &bpf_loader_upgradeable::upgrade(
            ctx.accounts.program.key,
            ctx.accounts.buffer.key,
            ctx.accounts.authority.key,
            ctx.accounts.spill.key,
        ),
        &ctx.accounts.to_account_infos(),
    )?;
    Ok(())
}

Example JSON Finding

{
  "detector": "anchor-upgrade-security",
  "severity": "critical",
  "confidence": 0.7,
  "message": "BPF Loader upgrade CPI without multi-sig or timelock protection",
  "location": { "function": "upgrade", "block": 0, "statement": 1 }
}

Detection Methodology

  1. Upgrade CPI detection: Identifies BPF Loader Upgradeable program CPI calls.
  2. Authority validation check: Verifies authority signer validation before upgrade.
  3. Timelock search: Looks for timestamp-based delay mechanisms.
  4. Multi-sig detection: Checks for multi-signature threshold validation.

Limitations

False positives: Programs managed by external multi-sig wallets (e.g., Squads) where governance occurs off-chain may be flagged. False negatives: Custom governance frameworks with non-standard patterns may not be recognized.

References