Timelock Operations
Detects timelock bypass vulnerabilities, missing delays for critical operations, and timestamp validation issues.
Timelock Operations
Overview
Remediation Guide: How to Fix Timelock Issues
The timelock operations detector identifies Solana programs where critical operations execute immediately without a required delay period, where timestamp validation is missing in time-dependent functions, and where timelock cancellation is not properly authorized. Timelocks give users time to react to pending changes (such as admin configuration updates or fund movements) and are a standard defense-in-depth mechanism.
Why This Is an Issue
Without timelocks, admin operations take effect immediately. This creates several risks:
- No user response window (CWE-367): Users cannot withdraw funds or take protective action before a malicious configuration change takes effect.
- Missing timestamp validation: Functions that depend on time but do not validate the clock can be exploited if the on-chain timestamp drifts or is manipulated within Solana’s tolerance window.
- Unprotected cancellation (CWE-284): If anyone can cancel a queued timelock operation, an attacker can prevent legitimate pending actions from executing.
Timelocks are especially important for programs that manage significant value, as they provide a safety window between announcement and execution of changes.
How to Resolve
Native Solana
use solana_program::{
account_info::AccountInfo, clock::Clock, program_error::ProgramError,
sysvar::Sysvar,
};
const TIMELOCK_DELAY: i64 = 86400; // 24 hours
pub fn execute_queued_action(accounts: &[AccountInfo]) -> ProgramResult {
let admin = &accounts[0];
let proposal = &accounts[1];
if !admin.is_signer {
return Err(ProgramError::MissingRequiredSignature);
}
let clock = Clock::get()?;
let proposal_data = proposal.try_borrow_data()?;
let queued_at = i64::from_le_bytes(proposal_data[0..8].try_into().unwrap());
// Validate timestamp is reasonable
if clock.unix_timestamp < queued_at {
return Err(ProgramError::InvalidArgument);
}
// Enforce delay period
if clock.unix_timestamp < queued_at + TIMELOCK_DELAY {
return Err(ProgramError::InvalidArgument); // Too early
}
// Safe to execute
Ok(())
}
Anchor
#[derive(Accounts)]
pub struct ExecuteProposal<'info> {
pub admin: Signer<'info>,
#[account(
mut,
has_one = admin @ ErrorCode::Unauthorized,
constraint = proposal.execute_after <= Clock::get()?.unix_timestamp @ ErrorCode::TimelockNotExpired
)]
pub proposal: Account<'info, Proposal>,
}
#[account]
pub struct Proposal {
pub admin: Pubkey,
pub execute_after: i64,
pub action: ProposalAction,
}
Examples
Vulnerable Code
pub fn update_admin(accounts: &[AccountInfo], new_admin: Pubkey) -> ProgramResult {
let admin = &accounts[0];
let config = &accounts[1];
if !admin.is_signer {
return Err(ProgramError::MissingRequiredSignature);
}
// VULNERABLE: immediate execution with no delay
let mut data = config.try_borrow_mut_data()?;
data[0..32].copy_from_slice(new_admin.as_ref());
Ok(())
}
Fixed Code
pub fn propose_admin_change(
accounts: &[AccountInfo],
new_admin: Pubkey,
) -> ProgramResult {
let admin = &accounts[0];
let proposal = &accounts[1];
let clock = Clock::get()?;
if !admin.is_signer {
return Err(ProgramError::MissingRequiredSignature);
}
// Queue the change with a delay
let mut data = proposal.try_borrow_mut_data()?;
data[0..32].copy_from_slice(new_admin.as_ref());
let execute_after = clock.unix_timestamp + TIMELOCK_DELAY;
data[32..40].copy_from_slice(&execute_after.to_le_bytes());
Ok(())
}
Sample Sigvex Output
{
"detector_id": "timelock",
"severity": "medium",
"confidence": 0.80,
"title": "Missing Timelock Delay for Critical Operation",
"description": "Critical operation is executed immediately without a required delay. Admins should be required to queue operations and wait for a delay period before execution, allowing users time to respond.",
"location": { "function": "execute_admin_action", "block": 0, "statement": 0 },
"cwe": 367
}
Detection Methodology
The detector analyzes time-dependent patterns in the function’s intermediate representation:
- Timestamp check tracking: Identifies comparisons involving parameter-range variables or clock sysvar constants that indicate timestamp validation.
- Delay validation detection: Looks for binary comparisons with constants in the realistic delay range (60 seconds to 1 year) that represent timelock enforcement.
- Critical operation identification: Flags parameter-range variable assignments in functions containing “execute” or “admin” in the name as critical operations requiring delays.
- Cancellation analysis: Detects cancellation-like operations and checks whether admin authorization (CheckKey, CheckOwner) precedes them.
- Timestamp validation gaps: Functions with “timelock” or “delay” in the name that lack timestamp checks generate findings.
- Context adjustment: Confidence is reduced for Anchor programs and read-only functions.
Limitations
False positives:
- Programs where the timelock is enforced in a separate instruction (propose/execute pattern) but the detector only sees the execute function.
- Anchor programs where time constraints are enforced in account validation.
False negatives:
- Timelocks implemented through CPI to external governance programs.
- Custom clock implementations that do not use the standard sysvar.
Related Detectors
- Admin Key Management — admin operations without proper key management
- Emergency Pause — missing ability to halt operations
- Multi-Sig Validation — multi-sig combined with timelock for defense in depth