# Cetus Protocol exploit (May 2025, Sui)

## 1. What happened

On **May 22, 2025**, Cetus Protocol, the largest DEX on the **Sui** blockchain, had its
concentrated-liquidity (CLMM) pools drained, triggering a sharp drop in pool depth and token
prices across Sui (https://blog.verichains.io/p/cetus-protocol-hacked-analysis,
https://slowmist.medium.com/slowmist-analysis-of-the-230-million-cetus-hack-ee569af040f2).
Attackers swapped a tiny deposit into an enormous liquidity position, then withdrew it; taken
assets were SUI, USDC, haSUI/vSUI and other Sui tokens
(https://slowmist.medium.com/slowmist-analysis-of-the-230-million-cetus-hack-ee569af040f2).

**Amount lost (sources disagree):**
- **~$223M** - rekt.news (https://rekt.news/cetus-rekt), Halborn (https://www.halborn.com/blog/post/explained-the-cetus-hack-may-2025), QuillAudits (https://quillaudits.medium.com/cetus-protocol-hack-overflow-bug-leads-to-223m-loss-0bafd07d83e9).
- **Over $260M** - Verichains' title/framing (https://blog.verichains.io/p/cetus-protocol-hacked-analysis).
- **Over $230M** - SlowMist (https://slowmist.medium.com/slowmist-analysis-of-the-230-million-cetus-hack-ee569af040f2).

**Recovery:** roughly **$162M was frozen** by Sui validators mid-heist, while
**$60M+ (~$62M, ~23,000 ETH)** crossed to Ethereum via Wormhole
(https://rekt.news/cetus-rekt, https://blog.verichains.io/p/cetus-protocol-hacked-analysis).
Cetus' post confirms the quarantined assets were retrieved by validator vote and relaunch at
3:00 UTC June 8, 2025
(https://medium.com/@CetusProtocol/cetus-relaunch-incoming-recovery-plan-and-the-road-ahead-9fc0f8bd5c41).

## 2. Root cause

This was a **smart-contract math bug, not a key or signer compromise**. The flaw lived in a shared
integer library (`@cetuspackages/inter-mate`, `math_u256::checked_shlw`), meant to detect overflow
when a 256-bit value is shifted left by 64 bits. Its guard used the wrong bound -
`0xffffffffffffffff << 192` instead of `1 << 192` - so almost every input passed. For any
`n >= 2^192`, `n << 64` silently wrapped modulo 2^256, collapsing the huge numerator in
`get_delta_a` to a tiny residue, so the token A needed to mint a given liquidity rounded to **1**
(https://blog.verichains.io/p/cetus-protocol-hacked-analysis,
https://slowmist.medium.com/slowmist-analysis-of-the-230-million-cetus-hack-ee569af040f2,
https://www.halborn.com/blog/post/explained-the-cetus-hack-may-2025). Cetus describes the vector
only generally as "a vulnerability in a CLMM-dependent open source library"
(https://medium.com/@CetusProtocol/cetus-relaunch-incoming-recovery-plan-and-the-road-ahead-9fc0f8bd5c41).
No dedicated Cetus post-mortem article could be located; their own reporting is the recovery post
and the Q2 2025 report (https://medium.com/@CetusProtocol/cetus-report-2025-q2-9d4f25a3eed9).

## 3. Pattern

**Integer overflow / faulty bounds check in fixed-width arithmetic (a precision bug).** The shape
is an overflow guard whose constant is wrong, letting a wrapped value flow into a division:

```
checked_shlw(n):
    mask = 0xffffffffffffffff << 192   // TOO LARGE
    if n > mask: revert                // almost never true
    else: return n << 64               // wraps mod 2^256 when n >= 2^192

get_delta_a(...):
    numerator = checked_shlw(full_mul(L, sqrt_price_diff))  // wrapped -> tiny
    return div_round(numerator, full_mul(p0, p1), round_up) // rounds to 1
```

An attacker opens a narrow tick range (300000-300200, ~1% wide), making the denominator `p0*p1`
huge; the wrapped numerator is smaller, `div_round` rounds to 1, and one unit of token A mints a
huge position
(https://slowmist.medium.com/slowmist-analysis-of-the-230-million-cetus-hack-ee569af040f2,
https://blog.verichains.io/p/cetus-protocol-hacked-analysis). The same shared function was
copy-pasted into Kriya, FlowX and Turbos (https://blog.verichains.io/p/multiple-sui-projects-previously).

## 4. The check that would have caught it

1. **Unit/fuzz test on the library primitive.** Assert `checked_shlw(n)` returns `(0, true)` for
   every `n >= 1 << 192` and exactly `n << 64` for `n < 1 << 192`; fuzz `n` over the whole `u256`
   range, asserting no silent wrap. Boundary tests at `n = (1<<192)-1` and `n = 1<<192` catch it
   (https://slowmist.medium.com/slowmist-analysis-of-the-230-million-cetus-hack-ee569af040f2).
2. **Invariant test at the pool level.** Invariant: *depositing `x` of token A never mints
   liquidity `L` for which `get_liquidity_from_a(L)` recovers more than `x`.* A fuzz/invariant run
   depositing a tiny amount into a ~1% tick range and checking withdrawable <= deposited + fees
   would have reverted this attack
   (https://blog.verichains.io/p/cetus-protocol-hacked-analysis,
   https://quillaudits.medium.com/cetus-protocol-hack-overflow-bug-leads-to-223m-loss-0bafd07d83e9).
3. **Review/process rule.** Treat shared math libraries as in-scope and audit the dependency, not
   just the core. Zellic stated the exploited `checked_shlw` lived in `inter-mate`, outside its
   April 2025 audit scope
   (https://rekt.news/cetus-rekt). Cetus' fix changed the mask to `1 << 192` and the condition to
   `n >= mask` (https://github.com/CetusProtocol/integer-mate/commit/06660f704c4ac1d443ab62346a46b5b60d49df33).

## 5. Sources

- https://medium.com/@CetusProtocol/cetus-relaunch-incoming-recovery-plan-and-the-road-ahead-9fc0f8bd5c41
- https://medium.com/@CetusProtocol/cetus-report-2025-q2-9d4f25a3eed9
- https://blog.verichains.io/p/cetus-protocol-hacked-analysis
- https://blog.verichains.io/p/multiple-sui-projects-previously
- https://slowmist.medium.com/slowmist-analysis-of-the-230-million-cetus-hack-ee569af040f2
- https://www.halborn.com/blog/post/explained-the-cetus-hack-may-2025
- https://quillaudits.medium.com/cetus-protocol-hack-overflow-bug-leads-to-223m-loss-0bafd07d83e9
- https://rekt.news/cetus-rekt
- https://github.com/CetusProtocol/integer-mate/commit/06660f704c4ac1d443ab62346a46b5b60d49df33
