Skip to main content
Sigvex

SPL Token ATA Validation

Detects improper Associated Token Account usage including wrong ATA, missing derivation validation, and mint mismatch.

SPL Token ATA Validation

Overview

Remediation Guide: How to Fix SPL Token ATA Validation

The ATA validation detector identifies programs that use token accounts without verifying they are the correct Associated Token Account for a given owner and mint. ATAs are deterministically derived PDAs; using an arbitrary token account instead of the correct ATA allows attackers to substitute accounts they control, redirecting funds or causing accounting errors.

Why This Is an Issue

Associated Token Accounts provide a canonical address for “owner X’s account for mint Y.” Without ATA derivation validation:

  • Wrong ATA: An attacker passes their own token account instead of the user’s ATA, receiving funds meant for the user
  • Mint mismatch: An ATA derived for a different mint is accepted, causing cross-token confusion
  • Missing rent exemption: Creating ATAs without rent validation can leave accounts below the rent-exempt minimum

CWE mapping: CWE-345 (Insufficient Verification of Data Authenticity).

How to Resolve

use spl_associated_token_account::get_associated_token_address;

pub fn transfer_to_user(accounts: &[AccountInfo], user: &Pubkey, mint: &Pubkey, amount: u64) -> ProgramResult {
    let user_ata = &accounts[0];

    // Verify ATA derivation
    let expected_ata = get_associated_token_address(user, mint);
    if user_ata.key != &expected_ata {
        return Err(ProgramError::InvalidAccountData);
    }

    // Proceed with transfer
    Ok(())
}

Examples

Vulnerable Code

pub fn send_tokens(accounts: &[AccountInfo], amount: u64) -> ProgramResult {
    let dest = &accounts[1]; // No ATA derivation check!
    let ix = spl_token::instruction::transfer(
        &spl_token::id(), accounts[0].key, dest.key, accounts[2].key, &[], amount,
    )?;
    invoke(&ix, accounts)?;
    Ok(())
}

Fixed Code

pub fn send_tokens(accounts: &[AccountInfo], amount: u64) -> ProgramResult {
    let dest = &accounts[1];
    let user = &accounts[3];
    let mint = &accounts[4];

    let expected = get_associated_token_address(user.key, mint.key);
    if dest.key != &expected {
        return Err(ProgramError::InvalidAccountData);
    }

    let ix = spl_token::instruction::transfer(
        &spl_token::id(), accounts[0].key, dest.key, accounts[2].key, &[], amount,
    )?;
    invoke(&ix, accounts)?;
    Ok(())
}

Sample Sigvex Output

{
  "detector_id": "spl-token-ata-validation",
  "severity": "high",
  "confidence": 0.78,
  "description": "Token operation uses account without ATA derivation validation. An attacker could substitute a different token account.",
  "location": { "function": "send_tokens", "offset": 2 }
}

Detection Methodology

  1. Token operation identification: Locates Transfer, MintTo, Burn, and other SPL Token CPI operations.
  2. Validation tracking: Tracks owner, key, and mint validation across basic blocks.
  3. ATA derivation detection: Looks for PDA derivation operations (find_program_address) that correspond to ATA address calculation.
  4. Gap analysis: Reports token accounts used in operations without corresponding ATA derivation checks.

Limitations

  • ATA derivation via get_associated_token_address may compile to patterns not recognized by heuristic detection.
  • Anchor’s associated_token::* constraints handle ATA validation automatically but may not be visible in decompiled output.

References