Deep analysis of SPL Token and Token-2022 program interactions
curl -s https://parity.cx/api/skills/token-analyzer | shcopyYou are performing a specialized analysis of how a Solana program interacts with SPL Token and Token-2022 (Token Extensions) programs. This skill goes deeper than the general security-audit on token-specific attack surfaces: mint authority abuse, transfer hook bypasses, metadata extension mishandling, and token account lifecycle errors.
Before starting analysis, fetch the following from the Parity repository:
| Source | Path | Contains |
|--------|------|----------|
| Vulnerability Rules | programs/parity/src/context_engine.rs > VULNERABILITY_RULES | Base vulnerability patterns including CPI safety and account validation |
| Curated Audit Findings | programs/parity/src/context_engine.rs > CURATED_AUDIT_FINDINGS | Real token-related vulnerabilities from OtterSec, Sec3, Neodyme |
| Framework Patterns | programs/parity/src/context_engine.rs > ANCHOR_PATTERNS | Correct CPI and account patterns for token operations |
| Security Audit Skill | skills/security-audit/SKILL.md | Base security checks that apply to all programs |
GitHub base URL: https://github.com/paritydotcx/Skills/blob/main/
Scan the program for all token-related operations and catalog them:
Mint operations:
MintTo / mint_to CPI callsTransfer operations:
Transfer / transfer CPI callsTransferChecked / transfer_checked usage (required for Token-2022)Burn operations:
Burn / burn CPI callsAccount management:
InitializeAccount / token account creationCloseAccount / token account closureFreezeAccount / ThawAccount operationsToken-2022 extensions (if applicable):
Build a complete map of which instructions perform which token operations.
For every mint operation, verify:
Vulnerable pattern:
// VULNERABLE: mint authority not validated, any signer can mint
let cpi_ctx = CpiContext::new(
ctx.accounts.token_program.to_account_info(),
MintTo {
mint: ctx.accounts.mint.to_account_info(),
to: ctx.accounts.destination.to_account_info(),
authority: ctx.accounts.mint_authority.to_account_info(), // unchecked
},
);Secure pattern:
// SECURE: PDA mint authority with seeds verification
let seeds = &[b"mint-authority", &[ctx.accounts.config.mint_auth_bump]];
let signer_seeds = &[&seeds[..]];
let cpi_ctx = CpiContext::new_with_signer(
ctx.accounts.token_program.to_account_info(),
MintTo {
mint: ctx.accounts.mint.to_account_info(),
to: ctx.accounts.destination.to_account_info(),
authority: ctx.accounts.mint_authority.to_account_info(),
},
signer_seeds,
);
require!(
ctx.accounts.mint.supply
.checked_add(amount)
.ok_or(ErrorCode::Overflow)? <= MAX_SUPPLY,
ErrorCode::SupplyCapExceeded
);Finding if violated:
For every transfer operation, check:
transfer_checked with explicit decimals. Using Transfer on Token-2022 mints will fail silently or bypass transfer hooks.Vulnerable pattern:
// VULNERABLE: uses Transfer instead of TransferChecked
// Will fail on Token-2022 mints with transfer hooks
token::transfer(cpi_ctx, amount)?;Secure pattern:
// SECURE: uses TransferChecked, compatible with both SPL Token and Token-2022
token::transfer_checked(cpi_ctx, amount, decimals)?;Finding if violated:
Verify token account creation and closure follows safe patterns:
- Balance must be zero before close (or explicitly transferred out)
- Lamport destination must be validated
- The close_authority must be the token account owner or a validated delegate
Vulnerable pattern:
// VULNERABLE: closing token account without checking balance
// Remaining tokens are burned, potentially losing user funds
token::close_account(cpi_ctx)?;Secure pattern:
// SECURE: verify balance is zero before closing
require!(
ctx.accounts.token_account.amount == 0,
ErrorCode::TokenAccountNotEmpty
);
token::close_account(cpi_ctx)?;Finding if violated:
Check that the program correctly handles token decimals:
Vulnerable pattern:
// VULNERABLE: assumes 6 decimals, breaks for mints with different precision
let ui_amount = raw_amount / 1_000_000;Secure pattern:
// SECURE: reads decimals from mint account
let decimals = ctx.accounts.mint.decimals;
let factor = 10u64.checked_pow(decimals as u32).ok_or(ErrorCode::Overflow)?;Finding if violated:
If the program is designed to work with Token-2022, verify:
Finding if applicable:
Verify ATA usage:
get_associated_token_address or equivalentcreate_associated_token_account or init_if_needed with proper constraintsFinding if violated:
| Severity | Penalty per finding |
|----------|-------------------|
| Critical | -25 |
| High | -15 |
| Medium | -8 |
| Info | -3 |
Start at 100. Subtract penalties. Floor at 0.
{
"score": 62,
"token_interactions": {
"mints": ["initialize_mint@L23", "mint_tokens@L67"],
"transfers": ["deposit@L45", "withdraw@L89"],
"burns": [],
"closures": ["close_vault@L112"],
"extensions_used": ["transfer_fee", "metadata_pointer"]
},
"findings": [
{
"severity": "critical",
"title": "Unvalidated mint authority in mint_tokens instruction",
"location": { "file": "lib.rs", "line": 67, "instruction": "mint_tokens" },
"description": "The mint_authority account is not validated against the config. Any account can be passed as mint authority.",
"recommendation": "Add has_one = mint_authority constraint on the config account, or use PDA-derived mint authority with seeds verification."
}
],
"summary": "1 critical, 2 high, 1 medium. Primary risk: unauthorized minting. Token-2022 compatibility: partial (missing transfer fee handling)."
}