Full Report
KyberSwap is a CLMM that was implemented from scratch. Concentrated Liquidity Market Makers (CLMM) are market makers where the liquidity is provided only within narrow bands. This allows for higher capital efficiency and less impermanent loss for LPs. CLMM price ranges are divided into ticks. Although they have a given number, they translate to the price of 1.0001t, where t is the tick. For a tick spacing of 10 in the price range $1.00-$1.22, you would deposit into the tick range (0,2000) because 1.00010 = 1.00 and 1.00012000 = 1.22. Each pool on KyberSwap consists of two tokens. When using a CLMM, a swap by a trader causes the price to shift. When this happens, the liquidity tick for the price goes to a different location, resulting in a sub-swap to occur. The degree of price impact is determined by the amount of liquidity inside a given tick range. There are three important invariants with CLMMs that should always be kept: Liquidity should never go below zero. When going between ticket range boundaries, the liquidity must either be increased or decreased. Should look like a normal distribution. The vulnerability literally lies on an edge case. When handling the edge between two ticks, the boundary edge cases had a major issue. When performing a one-for-zero (WHAT IS THIS) swap, the nextTick() function will be calculated as the currentTick, even though it crossed a boundary. Practically, this allows us to double add liquidity. How do we make money from this though? By getting our liquidity added *twice*, we can effectively steal funds from the protocol. Under the hood, the actual bug was in the backwards portion of the code. The first sub-swap cross the tick boundary, which is fine. On the second sub swap, the price difference is so small that is does not change. Hence, the sqrtP and nextSqrtP end up being the same, leading to a double add. The author wrote a proof of concept using a flash loan from Aave to drain the entire protocol of all its funds. The hacker got a large payout and no one lost money. Except, later on, a variant of this bug was found that stole all of the funds. Overall, an amazingly complicated bug with a good write up from the perspective of the author.
Analysis Summary
# Vulnerability: Double-Add Liquidity Logic Flaw in KyberSwap Elastic
## CVE Details
- **CVE ID**: N/A (DeFi protocols often use internal tracking; no CVE was assigned to this specific smart contract flaw)
- **CVSS Score**: 10.0 (Critical)
- **CWE**: CWE-682: Incorrect Calculation; CWE-841: Improper Enforcement of Behavioral Workflow
## Affected Systems
- **Products**: KyberSwap Elastic (Concentrated Liquidity Market Maker)
- **Versions**: Legacy `ks-elastic-sc` (Pre-May 2023 versions)
- **Configurations**: Specific to pools utilizing "Elastic" (CLMM) mechanics where swaps cross tick boundaries with extremely small price residues.
## Vulnerability Description
The vulnerability is a logic error in the swap engine of KyberSwap's Concentrated Liquidity Market Maker (CLMM). In a CLMM, liquidity is partitioned into "ticks." When a swap moves the price across a tick boundary, the protocol must update the active liquidity.
The flaw exists in the sub-swap calculation:
1. When a `one-for-zero` swap occurs, the engine calculates the distance to the `nextTick`.
2. If a sub-swap crosses a tick boundary but the remaining price impact is infinitesimally small, the `sqrtP` (current price) and `nextSqrtP` (target price) are calculated as identical due to rounding or precision handling.
3. Because the price didn't "move" but a boundary was reached, the `nextTick()` function returns the `currentTick` again.
4. This results in the protocol "crossing" the same tick boundary twice, effectively adding the same liquidity position to the active global liquidity twice.
## Exploitation
- **Status**: PoC available. Originally discovered via responsible disclosure (Saving $100M); however, a variant was later exploited in the wild in November 2023.
- **Complexity**: High (Requires deep understanding of CLMM math and precise manipulation of tick boundaries).
- **Attack Vector**: Network (Smart Contract Interaction via Flash Loans).
## Impact
- **Confidentiality**: None
- **Integrity**: High (Liquidity math is corrupted, allowing for artificial inflation of LP shares).
- **Availability**: High (Can be used to drain all collateral/TVL from the protocol).
## Remediation
### Patches
- Kyber Network released a new version of the Elastic contracts (post-May 2023) following an audit by **Chain Security**.
- Users were transitioned to `ks-elastic-sc-legacy` and then to the patched version.
### Workarounds
- During the initial discovery, the primary workaround was the **emergency withdrawal of liquidity** by LPs and the pausing of affected pools by the Kyber team.
## Detection
- **Indicators of Compromise**:
- Unexpectedly high liquidity values compared to deposited assets.
- Swap transactions involving extremely small price movements precisely at tick boundaries.
- Large flash loan volume from protocols like Aave preceding the drain.
- **Detection Tools**: Smart contract monitoring (e.g., Forta, Tenderly) to alert on `Swap` events where liquidity increases without a corresponding `Mint`.
## References
- KyberSwap Post-Mortem: [https://one-hundred-proof.github.io/kyberswap-post-mortem.html](https://one-hundred-proof.github.io/kyberswap-post-mortem.html)
- Chain Security Audit: [https://chainsecurity.com/security-audit/kyberswap-elastic/](https://chainsecurity.com/security-audit/kyberswap-elastic/)
- Proof of Concept: [https://github.com/one-hundred-proof/kyberswap-exploit](https://github.com/one-hundred-proof/kyberswap-exploit)