Denial Of Service in DeFi Liquidity Pools

The Initialization Vulnerability

Decentralized Exchanges (DEXs) have become a cornerstone of the DeFi ecosystem, processing billions in daily trading volume. However, during our recent security research at FuzzingLabs we uncovered a subtle yet significant vulnerability pattern that affects multiple DEX implementations. This vulnerability allows malicious actors to effectively disable newly created liquidity pools through initialization parameter manipulation.

The pattern is particularly interesting because it stems from common architectural decisions rather than implementation errors. While auditing various DEX protocols, we discovered that this vulnerability manifests in different forms but always follows the same core pattern: the ability to “poison” a pool during its initialization phase by setting critical parameters to extreme values.

This blog post details the technical aspects of this vulnerability pattern, its impact on DeFi protocols, and presents concrete mitigation strategies for protocol developers. Our goal is to raise awareness about this design pattern vulnerability and help the DeFi ecosystem build more robust protocols.

Case Study on Solana: DOS Vulnerability in Raydium CLMM Pool Initialization

Overview

The Raydium Concentrated Liquidity Market Maker (CLMM) implementation provided a clear example of how initialization parameter manipulation can lead to pool denial of service. This case study examines a vulnerability found in January 2024 that allowed attackers to render new pools inoperable by manipulating their activation timestamp.

Raydium CLMM Pool initialization dashboard

Technical Implementation

The vulnerability resided in the pool initialization code of the Raydium CLMM program. The critical section of code responsible for pool creation looked like this:

				
					pub struct CreatePool<'info> {
    /// Initialize an account to store the pool state
    #[account(
        init,
        seeds = [
            POOL_SEED.as_bytes(),
            amm_config.key().as_ref(),
            token_mint_0.key().as_ref(),
            token_mint_1.key().as_ref(),
        ],
        bump,
        payer = pool_creator,
        space = PoolState::LEN
    )]
    pub pool_state: AccountLoader<'info, PoolState>,

    // ... other accounts
}

pub fn create_pool(ctx: Context<CreatePool>, sqrt_price_x64: u128, open_time: u64) -> Result<()> {
    pool_state.initialize(
        bump,
        sqrt_price_x64,
        open_time,// No validation on open_time
        tick,
        ctx.accounts.pool_creator.key(),
    )?;

// ... remainder of initialization logic
}
				
			

The key vulnerability lay in the uniqueness of the pool_state for each token pair combination and the open_time parameter, which determined when the pool would become active for trading. This parameter was accepted without any bounds checking.

Vulnerability Analysis

The vulnerability stemmed from several architectural decisions in the Raydium implementation:

First, the protocol used a PDA (Program Derived Address) system that enforced unique pool addresses based on token pair combinations. This meant only one pool could exist for a given token pair with specific parameters.

				
					seeds = [
      POOL_SEED.as_bytes(),
      amm_config.key().as_ref(),
      token_mint_0.key().as_ref(),
      token_mint_1.key().as_ref(),
  ], // Pool address is derived from the tokens addresses
				
			

Second, the initialization function accepted the open_time parameter as a raw Unix timestamp without any validation against reasonable time bounds. There was no maximum limit on how far in the future this timestamp could be set.

				
					pub fn create_pool(ctx: Context<CreatePool>, sqrt_price_x64: u128, open_time: u64) -> Result<()> {
 // No boundaries on `open_time`
}
				
			

Finally, once initialized, the pool’s opening time could not be modified, making any malicious initialization effectively permanent.

Attack Scenario

Here’s how an attacker could exploit this vulnerability:

  1. Monitor new hype tokens that could be listed on Raydium
  2. Submit malicious pool creation transactions for common pairs (like Token/SOL or Token/USDC) with an extremely large open_time.
  3. The pool becomes unusable, as the specified open time will be far in the future. This prevents trading this token on the platform.

Alternatively, one could also frontrun initialization transactions:

  1. Monitor the Solana mempool for transactions calling the create_pool instruction on the Raydium CLMM program.
  2. When a legitimate pool creation is detected, extract the token pair and configuration
  3. Submit their own pool creation transaction with the same parameters but an extremely large open_time.


Impact Analysis

The exploitation of this vulnerability had several consequences for the Raydium ecosystem:

The affected token pair became unusable on the protocol until the specified open_time, which could be years or decades. Because the pool address was deterministic based on the token pair, no other pool could be created for these tokens.

Legitimate market makers and traders could not create any new trading pool.

Remediation Strategy

The vulnerability could have been addressed through several possible changes to the protocol:

  • Implementation of multiple pools support for the same token pair through additional identifier parameters (ex: Add a unique identifier in the pool’s PDA derivation seeds)
  • Introduction of governance-controlled recovery mechanisms for poisoned pools
  • Enhanced parameter validation across all pool initialization functions

Understanding the Core Pattern

Liquidity pools in DeFi protocols are particularly vulnerable to Denial of Service (DOS) attacks during their initialization phase due to a common architectural pattern. This vulnerability stems from how pools are typically designed and deployed.

The Fundamental Architecture

Most liquidity pool implementations follow these key architectural principles:

  1. Unique Pool Addresses: Each token pair can only have one pool with specific parameters (like fee tier or tick spacing). This uniqueness is typically enforced through:
    • Program Derived Addresses (PDAs) on Solana
    • Factory contract patterns on EVM chains
    • Deterministic address derivation based on parameters
  2. One-time Initialization: Pools can only be initialized once, and critical parameters are set during this initialization:
    • Initial price
    • Fee structures
    • Time locks
    • Trading boundaries
    • Liquidity thresholds

The Attack Vector

At the heart of these vulnerabilities lies a common pattern: the ability for malicious actors to “poison” new liquidity pools by frontrunning their initialization with deliberately harmful parameters. This attack vector is particularly interesting because it exploits the fundamental design of unique pool addresses in DeFi protocols.

1. Frontrunning

This attack follows a precise pattern that takes advantage of the transaction ordering nature of blockchain systems. When a legitimate creator attempts to deploy a new liquidity pool, their transaction must first pass through the mempool. During this period, attackers can monitor pool initialization transactions and analyze their parameters.
Upon detecting a new pool creation, the attacker can craft their own initialization transaction with identical pool parameters but modify critical values to render the pool unusable. By submitting this transaction with higher gas fees or transaction priorities, they ensure their malicious initialization executes before the legitimate one.

Note that instead of performing a frontrun transaction it is possible in some cases to predict the token pairs that people will want to initialize and execute the malicious initialization ahead of time.

2. Parameter Poisoning

In order to trigger a DOS of the pool you can manipulate the parameters used in the initialization process. Depending on the architecture you may be able to:

  • Set extreme initial prices (0 or maximum possible)
  • Configure far-future activation timestamps
  • Establish unreasonable trading boundaries

Any of these malicious initial parameters will make the pool unusable.

Best Practices for Protocol Designers

  1. Multiple Pool Support:
    • Allow multiple pools per token pair
    • Include unique identifiers in pool addresses derivation seeds
  2. Parameter Constraints:
    • Implement reasonable bounds for all parameters
    • Use oracle price feeds for validation
    • Set maximum time deltas
  3. Recovery Options:
    • Allow parameter updates for unused pools
    • Implement governance-controlled resets
    • Support pool deprecation and replacement

Conclusion

The initialization DOS vulnerability pattern we’ve explored demonstrates how subtle architectural decisions in DeFi protocols can lead to significant security implications. While our example focused on a bug we found on Solana programs, this vulnerability pattern is not chain-specific. Similar initialization parameter manipulation attacks could affect any smart-contract, including on Ethereum, BSC, or other EVM-compatible chains.

At FuzzingLabs, our security research helped numerous protocols strengthen their implementations against these and other vulnerability patterns. Whether you’re developing on Solana, Ethereum, or other chains, proper security review is essential before deployment.

Patrick Ventuzelo / @Pat_Ventuzelo

Mathieu Troullier / @mathieu_t

About Us

Founded in 2021 and headquartered in Paris, FuzzingLabs is a cybersecurity startup specializing in vulnerability research, fuzzing, and blockchain security. We combine cutting-edge research with hands-on expertise to secure some of the most critical components in the blockchain ecosystem.

Contact us for an audit or long term partnership!

Get Your Free Security Quote!

Let’s work together to ensure your peace of mind.

Keep in touch with us !

email

contact@fuzzinglabs.com

X (Twitter)

@FuzzingLabs

Github

FuzzingLabs

LinkedIn

FuzzingLabs

email

contact@fuzzinglabs.com

X (Twitter)

@FuzzingLabs

Github

FuzzingLabs

LinkedIn

FuzzingLabs