Skip to main content
Sigvex

Mint Authority Abuse

Detects token minting operations without proper mint authority validation, enabling unauthorized token supply inflation.

Mint Authority Abuse

Overview

Remediation Guide: How to Fix Mint Authority Abuse

The mint authority abuse detector identifies Solana programs that invoke SPL Token mint_to or mint_to_checked instructions without validating the mint authority account. When a program performs a CPI to the Token program to mint tokens but does not verify that the provided authority account is the legitimate mint authority, an attacker can supply their own account as the authority and mint unlimited tokens.

The detector uses CFG-aware dataflow analysis to track whether authority accounts have been validated (via signer checks, owner checks, or key checks) before reaching a mint CPI.

Why This Is an Issue

SPL Token minting requires the mint authority’s signature. If a program constructs a mint_to CPI and passes an unvalidated account as the authority:

  • An attacker provides their own keypair as the mint authority account
  • If the program does not check that this account matches the mint’s actual authority, the CPI may succeed with the attacker’s signature
  • The attacker mints arbitrary token amounts, inflating supply
  • Token holders suffer dilution, and the attacker can sell minted tokens for profit

This has been a recurring vulnerability pattern in Solana token programs and launchpad contracts.

CWE mapping: CWE-285 (Improper Authorization), CWE-269 (Improper Privilege Management).

How to Resolve

// Before: Vulnerable -- mint authority not validated
pub fn mint_tokens(accounts: &[AccountInfo], amount: u64) -> ProgramResult {
    let mint = &accounts[0];
    let destination = &accounts[1];
    let authority = &accounts[2];  // Not validated
    let token_program = &accounts[3];

    let ix = spl_token::instruction::mint_to(
        token_program.key,
        mint.key,
        destination.key,
        authority.key,  // Could be attacker's key
        &[],
        amount,
    )?;
    invoke(&ix, accounts)?;
    Ok(())
}

// After: Validate mint authority before CPI
pub fn mint_tokens(accounts: &[AccountInfo], amount: u64) -> ProgramResult {
    let mint = &accounts[0];
    let destination = &accounts[1];
    let authority = &accounts[2];
    let token_program = &accounts[3];

    // FIXED: verify authority is signer
    if !authority.is_signer {
        return Err(ProgramError::MissingRequiredSignature);
    }

    // FIXED: verify authority matches the mint's mint_authority
    let mint_data = mint.try_borrow_data()?;
    let mint_state = spl_token::state::Mint::unpack(&mint_data)?;
    if mint_state.mint_authority.unwrap() != *authority.key {
        return Err(ProgramError::InvalidAccountData);
    }

    let ix = spl_token::instruction::mint_to(
        token_program.key,
        mint.key,
        destination.key,
        authority.key,
        &[],
        amount,
    )?;
    invoke(&ix, accounts)?;
    Ok(())
}

Examples

Vulnerable Code

pub fn airdrop(accounts: &[AccountInfo], recipients: &[Pubkey], amount: u64) -> ProgramResult {
    let mint = &accounts[0];
    let authority = &accounts[1];
    let token_program = &accounts[2];

    // No check that authority == mint.mint_authority
    // No check that authority.is_signer
    for (i, recipient) in recipients.iter().enumerate() {
        let dest = &accounts[3 + i];
        let ix = spl_token::instruction::mint_to(
            token_program.key, mint.key, dest.key,
            authority.key, &[], amount,
        )?;
        invoke(&ix, accounts)?;
    }
    Ok(())
}

Fixed Code

pub fn airdrop(accounts: &[AccountInfo], recipients: &[Pubkey], amount: u64) -> ProgramResult {
    let mint = &accounts[0];
    let authority = &accounts[1];
    let token_program = &accounts[2];

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

    // FIXED: validate authority matches mint
    let mint_data = mint.try_borrow_data()?;
    let mint_state = spl_token::state::Mint::unpack(&mint_data)?;
    if mint_state.mint_authority.unwrap() != *authority.key {
        return Err(ProgramError::InvalidAccountData);
    }

    // FIXED: validate token program
    if token_program.key != &spl_token::id() {
        return Err(ProgramError::IncorrectProgramId);
    }

    for (i, _recipient) in recipients.iter().enumerate() {
        let dest = &accounts[3 + i];
        let ix = spl_token::instruction::mint_to(
            token_program.key, mint.key, dest.key,
            authority.key, &[], amount,
        )?;
        invoke(&ix, accounts)?;
    }
    Ok(())
}

Sample Sigvex Output

{
  "detector_id": "mint-authority-abuse",
  "severity": "critical",
  "confidence": 0.85,
  "description": "A token mint operation was detected without proper mint authority validation. An attacker could potentially mint unlimited tokens by providing a fake or compromised mint authority account.",
  "location": { "function": "airdrop", "offset": 4 }
}

Detection Methodology

The detector performs CFG-aware dataflow analysis:

  1. CPI identification: Scans for InvokeCpi statements that match mint instruction patterns (Token program CPI with mint-related account structures).
  2. Authority extraction: Identifies the authority variable from the CPI accounts list.
  3. Validation tracking: Uses SharedDataflowState to propagate signer checks, owner checks, and key checks across basic blocks. Tracks variable aliases so that let auth = accounts[2] followed by a check on auth is recognized.
  4. Vulnerability decision: If the authority variable reaches the mint CPI without any validation in a dominating block, the finding is emitted at Critical severity.
  5. Dataflow reuse: When available, reuses pre-computed dataflow results from earlier analysis stages to avoid redundant computation.

Limitations

False positives:

  • Programs that validate mint authority in a separate instruction (multi-instruction transaction pattern) may be flagged since cross-instruction validation is not tracked.
  • PDA-based mint authorities where the PDA derivation happens in a separate function may not be recognized.

False negatives:

  • Indirect mint operations through wrapper programs that obscure the mint_to CPI pattern.
  • Programs that validate authority through a governance vote stored in account state.

References