Skip to main content
Sigvex

Secondary Signer Validation Remediation

How to fix missing signer validation on identity-checked accounts.

Remediating Missing Secondary Signer Validation

Overview

Related Detector: Secondary Signer Validation

When an account is validated by address (CheckKey) but not by signer status (CheckSigner), anyone can reference that address without proving they control it. The fix is to add a signer check wherever an address check exists for authorization-critical accounts.

Before (Vulnerable)

use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey};

const AUTHORITY: Pubkey = /* authority address */;

pub fn authorized_action(accounts: &[AccountInfo]) -> ProgramResult {
    let authority = &accounts[0];

    // Only checks address -- anyone can pass AUTHORITY without signing
    if authority.key != &AUTHORITY {
        return Err(ProgramError::InvalidArgument);
    }

    perform_sensitive_operation()?;
    Ok(())
}

After (Fixed)

use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey};

const AUTHORITY: Pubkey = /* authority address */;

pub fn authorized_action(accounts: &[AccountInfo]) -> ProgramResult {
    let authority = &accounts[0];

    // Check identity
    if authority.key != &AUTHORITY {
        return Err(ProgramError::InvalidArgument);
    }

    // Check signer status
    if !authority.is_signer {
        return Err(ProgramError::MissingRequiredSignature);
    }

    perform_sensitive_operation()?;
    Ok(())
}

Alternative Mitigations

  1. Use the account-validation framework’s Signer type: The Signer<'info> account type enforces signer validation automatically.
#[derive(Accounts)]
pub struct AuthorizedAction<'info> {
    #[account(constraint = authority.key() == AUTHORITY @ ErrorCode::Unauthorized)]
    pub authority: Signer<'info>,
}
  1. PDA-based authorization: For program-controlled operations, use PDA signing via invoke_signed instead of relying on external signers. PDAs are validated by derivation, not by signer checks.

  2. Multi-sig pattern: For operations requiring multiple approvals, check signer status on all required co-signers, not just the primary signer.

if !co_signer_a.is_signer || !co_signer_b.is_signer {
    return Err(ProgramError::MissingRequiredSignature);
}

Common Mistakes

  • Adding signer check to PDA accounts: PDAs cannot sign transactions in the traditional sense. They sign via invoke_signed during CPI. Adding is_signer checks to PDA accounts will cause legitimate transactions to fail.
  • Checking signer on the wrong account: In multi-account instructions, ensure the signer check is on the authorization account, not on a data account or program account.
  • Relying on address check for authorization: Address checks prove identity, not intent. A known admin address can be referenced by anyone; only a signer check proves the admin actively authorized the transaction.
  • Missing signer check on secondary approvers: In multi-sig scenarios, developers often check the primary signer but forget secondary approvers. All co-signers must have both identity and signer validation.

References