SPL Token Close Authority Bypass
Detects token account closure without validating the close_authority field.
SPL Token Close Authority Bypass
Overview
Remediation Guide: How to Fix SPL Token Close Authority Bypass
The close authority bypass detector identifies programs that close or burn token accounts without validating the close_authority field. Token accounts have a dedicated close_authority field that specifies who can close the account. If a program does not read and compare this field against the signer, unauthorized parties can close accounts and drain the remaining SOL rent. This vulnerability appears in approximately 15% of recent Solana security audits.
Why This Is an Issue
SPL Token accounts have a close_authority field (an Option<Pubkey>) that designates who can close the account. When set, only that authority should be allowed to close the account. Without checking this field:
- Unauthorized closure: Attackers close accounts they do not control
- Rent theft: SOL rent from closed accounts is sent to the attacker’s address
- Protocol disruption: Closing protocol-owned accounts disrupts operations
- Token loss: If combined with insufficient balance checks, tokens may be lost
CWE mapping: CWE-863 (Incorrect Authorization).
How to Resolve
pub fn close_account_safe(accounts: &[AccountInfo]) -> ProgramResult {
let token_account = &accounts[0];
let destination = &accounts[1];
let authority = &accounts[2];
if !authority.is_signer {
return Err(ProgramError::MissingRequiredSignature);
}
// Read and validate close_authority
let token_data = Account::unpack(&token_account.data.borrow())?;
if let COption::Some(close_auth) = token_data.close_authority {
if *authority.key != close_auth {
return Err(ProgramError::Custom(ErrorCode::InvalidCloseAuthority as u32));
}
} else {
// No close_authority set -- owner can close
if *authority.key != token_data.owner {
return Err(ProgramError::InvalidAccountData);
}
}
let ix = spl_token::instruction::close_account(
&spl_token::id(), token_account.key, destination.key, authority.key, &[],
)?;
invoke(&ix, accounts)?;
Ok(())
}
Examples
Vulnerable Code
pub fn close_account(accounts: &[AccountInfo]) -> ProgramResult {
let token_account = &accounts[0];
let destination = &accounts[1];
let authority = &accounts[2]; // Not checked against close_authority!
// VULNERABLE: no close_authority validation
let ix = spl_token::instruction::close_account(
&spl_token::id(), token_account.key, destination.key, authority.key, &[],
)?;
invoke(&ix, accounts)?;
Ok(())
}
Sample Sigvex Output
{
"detector_id": "spl-token-close-authority-bypass",
"severity": "high",
"confidence": 0.82,
"description": "Token account closed without validating close_authority field. Unauthorized parties could close accounts and drain rent.",
"location": { "function": "close_account", "offset": 1 }
}
Detection Methodology
- Validation pass: Tracks field loads from token account data (specifically the close_authority field) and comparisons that validate the close authority.
- CPI pass: Identifies CloseAccount and Burn CPI operations.
- Gap analysis: Reports findings when close/burn operations occur without prior close_authority field access and comparison.
Limitations
- Close authority field access is detected via heuristic offset analysis; different token account layouts may not be recognized.
- The SPL Token program itself validates close authority during CPI execution, but program-level checks prevent unauthorized CPI attempts.
Related Detectors
- SPL Token Account Close — detects general close operation issues
- SPL Token Authority Confusion — detects authority type confusion
- Close Account Drain — detects close-and-drain patterns