Skip to main content
Sigvex

Lamport Dust Remediation

How to fix lamport dust exploitation vulnerabilities.

Lamport Dust Remediation

Overview

Related Detector: Lamport Dust

Lamport dust exploits programs that use exact equality on balances or fail to handle tiny residuals from rounding. The fix is to use inequality comparisons (<=, >=) instead of exact equality, zero both lamports and data on account closure, and round in favor of the protocol when calculating fees or distributions.

Before (Vulnerable)

// Vulnerable: exact equality allows dust bypass
if account.lamports() == 0 {
    return Err(ProgramError::AccountAlreadyClosed);
}

After (Fixed)

// Fixed: use inequality and clear all data on close
let balance = account.lamports();
require!(balance > 0, ProgramError::AccountAlreadyClosed);

**recipient.lamports.borrow_mut() += balance;
**account.lamports.borrow_mut() = 0;
account.data.borrow_mut().fill(0);  // Prevent resurrection

Alternative Mitigations

Anchor close Attribute

In an account-validation framework programs, use the close attribute which handles lamport transfer and data zeroing automatically:

#[derive(Accounts)]
pub struct CloseVault<'info> {
    #[account(mut, close = recipient)]  // Transfers all lamports, zeros data
    pub vault: Account<'info, Vault>,
    #[account(mut)]
    pub recipient: SystemAccount<'info>,
}

Common Mistakes

Mistake: Not Zeroing Account Data

// WRONG: transfers lamports but leaves data intact
**recipient.lamports.borrow_mut() += account.lamports();
**account.lamports.borrow_mut() = 0;
// Account data still has valid discriminator -- can be resurrected with 1 lamport

Mistake: Rounding Down User Withdrawals

// WRONG: truncation leaves dust in the protocol
let user_share = total_balance * user_tokens / total_supply;
// If user_tokens = 1 and total_supply = 3, user gets 0 -- dust stays in protocol

Round in the user’s favor on withdrawal, or accumulate remainders in a dedicated dust account.

References