Solana's Noisy Neighbor Attack: How Localized Fee Markets Let Attackers Block Your DeFi Liquidations
TL;DR: Solana's Localized Fee Markets (LFM) solved global congestion — but introduced a surgical denial-of-service vector. By flooding write-locks on a single protocol's state accounts, an attacker can price out keeper bots during the exact moments liquidations matter most. We break down the attack mechanics, show real detection patterns, and provide a state-sharding migration guide.
The Promise That Became a Weapon
When Solana introduced Localized Fee Markets via SIMD-0110, it was hailed as an elegant solution to network-wide congestion. Instead of every transaction competing in a single global fee auction, fees became localized — you only paid premium rates when contending for the same state accounts as other transactions.
The theory was sound: a spike in NFT minting shouldn't make your DeFi swap expensive. Each "hot" account gets its own micro-market.
But here's the thing about micro-markets: they can be cornered.
Anatomy of the Noisy Neighbor Attack
The Setup
Consider a typical Solana DeFi lending protocol — let's call it LendProtocol. Like most Solana programs, it uses a handful of global state accounts:
GlobalState PDA → Tracks total deposits, borrows, utilization
MarketReserve PDA → Per-asset reserve data
OracleBuffer PDA → Cached price feeds
LiquidationQueue PDA → Pending liquidation orders
Every liquidation, deposit, borrow, and repay instruction needs a write lock on at least GlobalState and MarketReserve. This means all these transactions are competing in the same Localized Fee Market.
The Attack
Reconnaissance: The attacker maps the protocol's write-lock dependency graph. They identify the 2-3 PDAs that appear as writable accounts in >80% of the protocol's transactions.
Trigger Detection: The attacker monitors CEX prices (via websocket feeds to Binance, OKX, etc.) for volatile moves that will trigger on-chain liquidations once oracle prices update.
Fee Floor Flooding: When a liquidation-triggering price move is detected, the attacker submits hundreds of no-op transactions that request write locks on the protocol's global state PDAs:
// Attacker's "noisy" program
pub fn process_instruction(
_program_id: &Pubkey,
accounts: &[AccountInfo],
_data: &[u8],
) -> ProgramResult {
// Request write lock on target PDAs
// Do nothing. Just occupy the fee market.
Ok(())
}
Each transaction includes a high priority fee — but the attacker doesn't need to outbid everyone forever. They just need to push the localized base fee high enough that keeper bots' pre-configured fee caps are exceeded.
- Liquidation Window Closes: With keepers priced out, the protocol's underwater positions remain unliquidated through the volatile period. The attacker, who holds a leveraged position that would have been liquidated, survives. Or worse — they're simultaneously shorting the protocol's governance token, profiting from the insolvency event.
Cost Analysis
This is the terrifying part. Because Localized Fee Markets only affect transactions touching the same state accounts, the attacker's cost is dramatically lower than a global DoS:
- Global Solana DoS (pre-LFM): ~$50,000+/min, affects everything
- Localized Fee Market DoS: ~$200-2,000/min, targets single protocol
- Ethereum gas price manipulation: ~$10,000+/min, affects everyone in same block
A few thousand dollars per minute to selectively freeze a protocol holding $100M+ in user funds. The economics are heavily in the attacker's favor.
The Firedancer Amplification
The 2026 rollout of Firedancer makes this worse. Under the Alpenglow consensus model with SIMD-0370's dynamic block sizing, high-performance leaders can produce blocks with hundreds of millions of Compute Units. This means:
- More transaction slots for the attacker to fill with noise
- Higher throughput means more write-lock contention can be generated per slot
- Skip-vote dynamics create finality uncertainty that extends the attack window
A liquidation bot that waits for Finalized commitment (the safe choice) now faces 2-3x longer confirmation times during periods of validator heterogeneity. Combined with LFM DoS, the keeper is both priced out and unsure when their transaction will actually land.
Detection: How to Spot It Happening
Pattern 1: Fee Spike Isolation
Monitor your protocol's localized base fee independently from the global base fee:
# Pseudo-code for LFM anomaly detection
def detect_noisy_neighbor(protocol_accounts, window_slots=10):
local_fee = get_localized_base_fee(protocol_accounts, window_slots)
global_fee = get_global_base_fee(window_slots)
ratio = local_fee / max(global_fee, 1)
if ratio > 5.0: # Local fee 5x+ above global
alert(f"LFM anomaly: local/global ratio = {ratio:.1f}")
# Check if spike correlates with oracle volatility
oracle_vol = get_price_volatility(window_slots)
if ratio > 3.0 and oracle_vol > THRESHOLD:
alert("CRITICAL: Possible Noisy Neighbor during volatility event")
Pattern 2: Write-Lock Concentration
Track unique signers requesting write-locks on your PDAs:
def detect_write_lock_concentration(pda_pubkey, window_slots=5):
txns = get_recent_write_lock_txns(pda_pubkey, window_slots)
signer_counts = Counter(tx.signer for tx in txns)
total = len(txns)
# If top 3 signers account for >60% of write locks
top3_share = sum(c for _, c in signer_counts.most_common(3)) / total
if top3_share > 0.6:
alert(f"Write-lock concentration: top 3 signers = {top3_share:.0%}")
Pattern 3: No-Op Transaction Fingerprinting
Attacker transactions have a distinctive profile — they request write locks but perform minimal computation:
- CU consumed << CU requested: The transaction requests maximum CUs but uses <5,000
- No meaningful state changes: The writable accounts are not actually modified
- Repetitive instruction data: Same program, same accounts, same (empty) data across hundreds of transactions
Mitigation: The State-Sharding Playbook
The fundamental fix is reducing write-lock contention on global state. Here's the migration path:
Step 1: Identify Hot Accounts
# Using Helius API to map write-lock hotspots
curl -s "https://api.helius.xyz/v0/addresses/{PROGRAM_ID}/transactions?api-key=KEY&limit=1000" \
| jq '[.[] | .accountData[] | select(.writable == true) | .account] | group_by(.) | map({account: .[0], count: length}) | sort_by(-.count) | .[0:5]'
Any account appearing as writable in >10% of your traffic is a high-severity LDoS target.
Step 2: Shard Global State
Replace single-PDA global state with user-derived shards:
// BEFORE: Single global state (LDoS vulnerable)
#[derive(Accounts)]
pub struct Deposit<'info> {
#[account(mut, seeds = [b"global_state"], bump)]
pub global_state: Account<'info, GlobalState>,
// ...
}
// AFTER: Sharded state (LDoS resistant)
#[derive(Accounts)]
pub struct Deposit<'info> {
#[account(
mut,
seeds = [b"user_shard", user.key().as_ref()],
bump
)]
pub user_shard: Account<'info, UserShard>,
// Global aggregation happens asynchronously via cranks
}
Step 3: Implement Priority Fee Escalation in Keepers
Keeper bots must dynamically respond to localized fee spikes:
async def submit_liquidation(tx, protocol_accounts):
base_fee = await get_localized_fee(protocol_accounts)
# Exponential escalation with economic ceiling
max_profitable_fee = calculate_liquidation_profit(tx) * 0.8
for attempt in range(MAX_ATTEMPTS):
priority_fee = min(
base_fee * (1.5 ** attempt),
max_profitable_fee
)
result = await send_transaction(tx, priority_fee)
if result.confirmed:
return result
# If all attempts fail, trigger protocol-level circuit breaker
await trigger_emergency_pause(reason="keeper_priced_out")
Step 4: Protocol-Level Circuit Breakers
If liquidations can't execute for N consecutive slots, the protocol should automatically:
- Pause new borrows (prevent further bad debt accumulation)
- Widen liquidation bonus (incentivize liquidators to bid higher)
- Activate emergency oracle mode (switch to TWAP to reduce manipulation surface)
pub fn check_liquidation_health(ctx: Context<CrankCheck>) -> Result<()> {
let state = &mut ctx.accounts.protocol_state;
let current_slot = Clock::get()?.slot;
if current_slot - state.last_successful_liquidation_slot > STALE_THRESHOLD {
state.emergency_mode = true;
state.borrow_paused = true;
state.liquidation_bonus_bps += EMERGENCY_BONUS_INCREMENT;
emit!(EmergencyModeActivated {
slot: current_slot,
stale_slots: current_slot - state.last_successful_liquidation_slot,
});
}
Ok(())
}
The Bigger Picture: Why This Matters Now
Q1 2026 has already seen ~$137M in DeFi exploits. The Step Finance incident ($27M via compromised keys), the Resolv stablecoin exploit ($25M via unbacked minting), and the CrossCurve bridge drain ($3M) all targeted different vectors — but the Noisy Neighbor attack combines economic incentive alignment with low barrier to entry in a way none of these did.
The attacker doesn't need:
- ❌ A smart contract bug to exploit
- ❌ A compromised private key
- ❌ A flash loan for capital
- ❌ Complex cross-chain bridging
They just need:
- ✅ SOL for transaction fees (~$2,000 in the worst case)
- ✅ A leveraged position they want to protect
- ✅ Knowledge of the target protocol's state account layout
This is not theoretical. The write-lock dependency graphs of the top 20 Solana DeFi protocols are public. Every account a program touches is visible on-chain. The only question is when — not if — we see this exploited at scale.
Checklist: Is Your Protocol Vulnerable?
- Global state PDAs: Sharded by user/market ✅ vs Single PDA for all operations ❌
- Write-lock concentration: <10% of traffic on any single account ✅ vs >10% on 1+ accounts ❌
- Keeper fee strategy: Dynamic escalation with profit ceiling ✅ vs Static priority fee ❌
- Circuit breaker: Auto-pause after N stale slots ✅ vs None ❌
- LFM monitoring: Real-time local/global fee ratio alerts ✅ vs No monitoring ❌
- Liquidation commitment: Configurable (Confirmed → Finalized) ✅ vs Hardcoded ❌
If you checked ❌ on 3+ items, your protocol is a Noisy Neighbor target today.
References
- SIMD-0110: Localized Fee Markets
- SIMD-0370: Dynamic Block Sizing
- Zealynx: Solana Audit Guide 2026
- Firedancer Validator Documentation
- Q1 2026 DeFi Exploit Summary — CCN
This article is part of the DreamWork Security research series on emerging blockchain attack vectors. Follow for weekly deep dives into DeFi security, audit tooling, and vulnerability analysis.
Top comments (0)