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
- Token operation identification: Locates Transfer, MintTo, Burn, and other SPL Token CPI operations.
- Validation tracking: Tracks owner, key, and mint validation across basic blocks.
- ATA derivation detection: Looks for PDA derivation operations (find_program_address) that correspond to ATA address calculation.
- Gap analysis: Reports token accounts used in operations without corresponding ATA derivation checks.
Limitations
- ATA derivation via
get_associated_token_addressmay 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.
Related Detectors
- Token Account Spoofing — detects fake token account substitution
- PDA Validation — detects general PDA validation issues