Imbalanced Liquidity
id: LS38H
title: Imbalanced Liquidity
baseSeverity: H
category: amm-liquidity
language: solidity
blockchain: [ethereum, arbitrum, optimism, avalanche, polygon, bsc]
impact: Value leakage, frontrun withdrawals, or pool destabilization
status: draft
complexity: medium
attack_vector: external
mitigation_difficulty: medium
versions: [">=0.6.0", "<=0.8.25"]
cwe: CWE-670
swc: SWC-131
๐ Description
- In liquidity pools that support multi-asset deposits or withdrawals (e.g., Curve, Balancer, stable AMMs), imbalanced liquidity occurs when:
- Users deposit or withdraw assets in an asymmetric manner (e.g., only DAI in a DAI/USDC/USDT pool)
- The protocol does not adjust pricing curves or pool shares to penalize imbalanced actions
- If no protections exist (e.g., slippage loss, fee curves, invariant checks), attackers can:
- Withdraw more value than deposited by abusing the pool imbalance
- Arbitrage between tokens before or after interacting with the pool
- Exploit single-sided liquidity additions for economic advantage
๐จ Vulnerable Code
pragma solidity ^0.8.0;
contract ImbalancedPool {
mapping(address => uint256) public balancesDAI;
mapping(address => uint256) public balancesUSDC;
uint256 public totalDAI;
uint256 public totalUSDC;
function depositDAI(uint256 amount) external {
balancesDAI[msg.sender] += amount;
totalDAI += amount;
// โ no consideration for USDC imbalance
}
function withdrawProportional() external {
uint256 share = balancesDAI[msg.sender] / totalDAI;
uint256 usdcOut = totalUSDC * share; // โ attacker gets outsized USDC if DAI dominates
totalUSDC -= usdcOut;
// send USDC to msg.sender (omitted)
}
}
๐งช Exploit Scenario
- An attacker deposits 1,000,000 DAI into a pool with 1 DAI and 1,000,000 USDC.
- They now own ~99.99% of the pool.
- They call withdrawProportional() and receive ~999,990 USDC.
- The pool is drained of USDC, and DAI remains over-concentrated.
- Arbitrageurs capitalize on the imbalance, further degrading the pool.
Assumptions:
- No invariant (e.g., constant product or stable curve) protects multi-asset ratio
- No slippage penalty or withdrawal fee is applied to unbalanced exits
โ Fixed Code
pragma solidity ^0.8.0;
contract BalancedPool {
mapping(address => uint256) public shares;
uint256 public totalShares;
uint256 public totalDAI;
uint256 public totalUSDC;
function deposit(uint256 daiIn, uint256 usdcIn) external {
require(daiIn > 0 && usdcIn > 0, "Must deposit both assets");
uint256 newShares = daiIn + usdcIn; // Simplified invariant
shares[msg.sender] += newShares;
totalShares += newShares;
totalDAI += daiIn;
totalUSDC += usdcIn;
}
function withdraw(uint256 shareAmount) external {
require(shareAmount <= shares[msg.sender], "Too much");
uint256 daiOut = (totalDAI * shareAmount) / totalShares;
uint256 usdcOut = (totalUSDC * shareAmount) / totalShares;
shares[msg.sender] -= shareAmount;
totalShares -= shareAmount;
totalDAI -= daiOut;
totalUSDC -= usdcOut;
// send daiOut and usdcOut to user (omitted)
}
}
๐งญ Contextual Severity
- context: "DEX or oracle system relies on pool balance for price feeds"
severity: H
reasoning: "Attackers can manipulate price and extract profit or oracle control"
- context: "Liquidity pool not connected to external price systems"
severity: M
reasoning: "Users suffer slippage, but no oracle exposure"
- context: "Only cosmetic imbalance or managed via rebalance bots"
severity: L
reasoning: "No direct impact on functionality"
๐ก๏ธ Prevention
Primary Defenses
- Apply invariant-based math (e.g., constant sum/product, stable-swap equations)
- Reject or penalize single-sided deposits or withdrawals
Additional Safeguards
- Add withdrawal fees for imbalanced exits
- Track per-token accounting per user (e.g., Curveโs LP share weighting)
- Use slippage tolerances and simulate impact before confirming
Detection Methods
- Identify liquidity functions with unconstrained ratio logic
- Test protocol under extreme imbalance conditions
- Tools: Manual review, invariant testing (Foundry, Echidna), Slither
๐ฐ๏ธ Historical Exploits
- Name: Uranium Finance Exploit
- Date: 2021-04-28
- Loss: ~$50 million stolen due to incorrect token ratio in liquidity pool initialization
- Post-mortem: Link to post-mortem
๐ Further Reading
โ Vulnerability Report
id: LS38H
title: Imbalanced Liquidity
severity: H
score:
impact: 4
exploitability: 4
reachability: 4
complexity: 2
detectability: 4
finalScore: 3.9
๐ Justifications & Analysis
- Impact: Pools may be drained or users receive outsized value
- Exploitability: Easily triggered by manipulating deposit/withdraw pattern
- Reachability: Present in many AMMs or vaults without invariant enforcement
- Complexity: Conceptually simple to abuse once mechanics are known
- Detectability: Highly visible in code and sim testing, but may be overlooked