Skip to main content
Sigvex

Program Upgrade Risks

Detects security risks in upgradeable Solana programs including authority validation issues.

Program Upgrade Risks

Overview

The program upgrade risks detector identifies security issues in upgradeable Solana programs, including unprotected upgrade authority, missing authority validation before upgrade operations, authority transfer without proper checks, and single points of failure in the upgrade path.

For remediation guidance, see Program Upgrade Risks Remediation.

Why This Is an Issue

Upgradeable programs on Solana can have their code replaced by the upgrade authority at any time. If the authority is a single keypair without multi-signature or timelock protection, a compromised key allows an attacker to replace the program with malicious code, stealing all funds held by the program. Programs that do not validate the upgrade authority before upgrade operations are vulnerable to unauthorized code replacement.

How to Resolve

Before (Vulnerable)

// Vulnerable: single authority, no timelock
pub fn upgrade_program(ctx: Context<Upgrade>) -> Result<()> {
    // No validation of authority
    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: validated authority with timelock
pub fn upgrade_program(ctx: Context<Upgrade>) -> Result<()> {
    require!(
        ctx.accounts.authority.key() == ctx.accounts.config.upgrade_authority,
        ErrorCode::Unauthorized
    );
    let config = &ctx.accounts.config;
    let clock = Clock::get()?;
    require!(
        clock.unix_timestamp >= config.upgrade_requested_at + TIMELOCK_DURATION,
        ErrorCode::TimelockNotExpired
    );

    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": "program-upgrade-risks",
  "severity": "high",
  "confidence": 0.7,
  "message": "Upgrade authority not validated before BPF Loader upgrade CPI",
  "location": { "function": "upgrade_program", "block": 0, "statement": 1 }
}

Detection Methodology

  1. Upgrade CPI detection: Identifies CPI calls to the BPF Loader Upgradeable program.
  2. Authority validation search: Checks for signer and ownership validation on the upgrade authority account.
  3. Authority transfer tracking: Flags authority transfers to arbitrary addresses without multi-sig.
  4. Timelock detection: Looks for timestamp-based delay mechanisms on upgrade operations.

Limitations

False positives: Programs managed by multi-sig wallets at the infrastructure level (outside program code) may be flagged. False negatives: Authority validation in separate governance programs is not detected.

References