Clober DEX Liquidity Vault / Rebalancer burnHook Malicious-Strategy Reentrancy Drain (2024-12-10)
- Name: Clober DEX Liquidity Vault / Rebalancer
burnHookmalicious-strategy reentrancy drain - Date: 2024-12-10
- Protocol: Clober DEX Liquidity Vault / Rebalancer
- Chain: Base
- Category: reentrancy / arbitrary strategy admission / hook-ordering failure / liquidity-vault drain
- Loss: about
133.7 ETHon Base, roughly$501kat the time - Summary: Clober’s Base-side liquidity vault let anyone open a pool with an arbitrary
strategycontract, then trusted that strategy during the LP burn flow. In the vulnerable Rebalancer, burning LP shares did not fully close the accounting boundary before callingpool.strategy.burnHook(...). The attacker flash-borrowed267.4 WETH, opened a WETH/fake-token pool with a malicious strategy they controlled, minted LP shares, and then usedburnHookto re-enter the burn path while the first burn still relied on stale reserve state. That let the inner and outer burns both cash out against effectively the same WETH reserves. The attacker withdrew about401.1 WETHfrom a pool funded with only267.4 WETH, repaid the flash loan principal, and kept roughly133.7 ETHas profit. - Trigger / entry point:
- The exploited contract was Clober’s Base Rebalancer / Liquidity Vault at
0x6A0b87D6b74F7D5C92722F6a11714DBeDa9F3895. - Public incident reports identify the main exploit transaction as
0x8fcdfcded45100437ff94801090355f2f689941dca75de9a702e01670f361c04. - Clober’s
open()path accepted a caller-suppliedstrategyaddress for a new pool. - The attacker used that freedom to register their own malicious strategy contract, then later invoked
burn()so the vault would call back into attacker-controlled logic throughburnHook.
- The exploited contract was Clober’s Base Rebalancer / Liquidity Vault at
- Root cause:
- Clober treated a user-supplied strategy contract as trusted execution inside the LP lifecycle.
- The burn path handed control to
pool.strategy.burnHook(...)before the protocol had made the whole burn operation non-reenterable in practice. - Because the callback fired while the first burn still depended on pre-finalized accounting, the attacker could re-enter
burn()and make the vault compute a second withdrawal against reserve state that had not been safely sealed against that nested call. - The deeper failure was not just
missing nonReentrant; it was letting arbitrary per-pool strategy code sit directly on the asset-withdrawal boundary.
- Exploit path:
- The attacker used Morpho Blue to flash-loan
267.4 WETH. - They deployed or used a malicious strategy contract at
0x32Fb1BedD95BF78ca2c6943aE5AEaEAAFc0d97C1and a fake paired token at0xd3c8d0cd07Ade92df2d88752D36b80498cA12788. - They called Clober’s
open()flow to create a new pool keyed to the WETH/fake-token pair while setting the strategy to their malicious contract. - They minted LP shares by providing
267.4 WETHand the matching nominal amount of the fake token. - They initiated a
burn()call for part of the LP position. - During that burn, Clober invoked
pool.strategy.burnHook(...)on the attacker-controlled strategy. - The malicious hook re-entered the vault’s burn path before the first withdrawal flow had been safely closed, so the nested burn could still cash out against reserve/accounting assumptions the outer frame was already using.
- Across the inner and outer burns, the attacker extracted about
401.1 WETHfrom a pool that only ever held267.4 WETHof real value. - They repaid the
267.4 WETHflash loan and kept the surplus133.7 ETH, then bridged proceeds from Base to Ethereum.
- The attacker used Morpho Blue to flash-loan
- What the attacker needed to be true:
- Clober needed to allow arbitrary caller-supplied strategy contracts during pool creation.
- The strategy contract needed a reachable callback like
burnHookduring asset withdrawal. - The burn flow needed to be re-enterable, or otherwise still rely on stale reserve/accounting state when the hook fired.
- The attacker needed one real asset side with meaningful value (
WETH) and one attacker-controlled side that was cheap to fabricate. - The pool only needed enough real WETH for the protocol to overpay the nested burn sequence; the fake token side did not need outside market value.
- Technical anatomy worth remembering:
- This was not a generic
random user drains arbitrary poolevent. The attacker first created a pool whose strategy boundary they controlled, then used that boundary as the reentrancy trampoline. - The fake-token leg mattered because it let the attacker satisfy Clober’s pool-creation and minting flow without contributing a second real asset.
- The profitable step was not the mint; it was the burn, where one LP position was unwound through nested callbacks against incompletely finalized reserve logic.
- The incident is a useful reminder that plugin-style strategy architecture widens the attack surface even when the strategy interface itself looks narrow. A hook that is “just for strategy bookkeeping” becomes a custody surface the moment it runs during mint or burn.
- Reports on the exact storage-write ordering differ in emphasis, but they agree on the operational invariant failure:
burnHookwas reachable early enough for attacker-controlled code to re-enter and make the vault overpay WETH on exit.
- This was not a generic
- Representative transactions and addresses:
- Vulnerable Rebalancer / Liquidity Vault:
0x6A0b87D6b74F7D5C92722F6a11714DBeDa9F3895 - Exploit transaction:
0x8fcdfcded45100437ff94801090355f2f689941dca75de9a702e01670f361c04 - Attacker Base EOA:
0x012Fc6377F1c5CCF6e29967Bce52e3629AaA6025 - Attack strategy contract:
0x32Fb1BedD95BF78ca2c6943aE5AEaEAAFc0d97C1 - Fake paired token used in public analyses:
0xd3c8d0cd07Ade92df2d88752D36b80498cA12788 - Post-bridge Ethereum recipient addresses highlighted in incident reports:
0x7760d838192f6e526721a0f6b160627bae989a3eand0x711c87a0767101fa6f3893facb670b5689621e23
- Vulnerable Rebalancer / Liquidity Vault:
- Response / mitigation:
- Clober publicly disclosed the incident, said the breach was limited to the Base Liquidity Vault, and stated that the core order-book protocol remained unaffected.
- The team offered the attacker a
20%bounty in exchange for returning the remaining funds. - Post-incident discussion focused heavily on the gap between prior audits and the code/users actually exposed to the exploit path, especially around post-audit changes and the live hook surface in the vault.
Pattern tags
- reentrancy
- callback-frame-authority-reuse
- interface-conformance-semantic-compatibility-failure
- privilege-stripped-external-execution-and-inventory-scoped-trampolines
- The preserved failure was not merely
missing nonReentrant; it was that Clober let a user-authored strategy interface become part of the live burn authority of a reserve-bearing vault, then left the outer burn frame authoritative enough that the hook could spend the same WETH-side reserve assumptions twice. - Clober is therefore a clean
attacker-chosen plugin becomes withdrawal-path authoritycase, not just a genericDEX got reenteredanecdote.
Why the exploit worked
open()treatedstrategylike a configuration field rather than like a trust boundary. Once the attacker could register their own contract there, Clober had already admitted untrusted code onto the mint / burn path of a real-asset pool.- The burn flow then authenticated the wrong object. It acted as if
this contract satisfies the strategy interface for this poolalso meantthis callback is safe to run before reserve and withdrawal state are sealed, which is exactly the semantic leap the attacker monetized. burnHookfired while the outer burn still depended on pre-finalized reserve state, so the nested burn inherited a live withdrawal frame that still described the pool as if the first withdrawal had not already spent part of its WETH-side inventory.- The fake-token leg mattered because it collapsed the attacker’s capital requirement to one real asset side. Clober did not need both pool assets to be money-good for the burn to overpay; it only needed the WETH-side reserve math to remain authoritative during re-entry.
- Put differently: the hook was not ancillary bookkeeping. It was an execution surface sitting directly on the custody boundary, and the vault let that surface observe and reuse half-finished withdrawal truth.
Detection and audit pivots
- Treat user-supplied plugin endpoints like custody surfaces when they run during
mint,burn,rebalance,withdraw, or any path that computes how much real inventory leaves the system. - Fuzz full pool-lifecycle sequences rather than isolated function calls:
open(attacker strategy) -> mint(real asset + fake asset) -> burn() -> burnHook() -> nested burn()is the meaningful adversarial trace here. - Ask whether interface conformance is being mistaken for trustworthiness. If
strategy,hook,market, oradapteris accepted because it exposes the right methods, what prevents a malicious implementation from re-entering or redefining the economic meaning of the flow? - Audit reserve sealing order, not just transfer order. The critical question is
what exact reserve / share / withdrawal object remains authoritative when the callback fires, whether the external edge is a token transfer, a strategy hook, or both. - Model one-real-asset / one-worthless-asset pools explicitly. If a vault can be opened against an attacker-fabricated sidecar asset, then the real review question is whether the protocol can be tricked into overpaying the money-good side on exit.
- Review whether flexible strategy execution is inventory-scoped. The healthier architecture is usually to run arbitrary plugin logic in a stripped-down trampoline that cannot directly inherit reserve-bearing burn authority from the vault.
Why this incident matters
- It preserves a very clean
attacker-chosen plugin hook becomes the reentrancy primitivevariant of a familiar bug class. - It shows that letting users install arbitrary strategy code is not merely an extensibility feature; it becomes part of the protocol’s withdrawal trust boundary.
- It is also a compact example of why fake-asset pool legs matter in exploit design: the attacker only needed one side of the pool to be real, as long as the vulnerable burn math would still honor LP claims against the real side.
- The sharper healthy-side lesson is architectural: when flexible per-pool strategy logic is a product feature, the vault still has to prove that strategy execution never inherits reserve-bearing authority broad enough to turn one in-flight burn into two withdrawals.
Failure-prevention checklist
- Treat
strategyadmission as privileged code admission, not as harmless pool configuration. If user-created pools may point at strategy code, the vault should either whitelist reviewed implementations or strictly confine strategy execution to an inventory-free trampoline that cannot inherit burn or withdrawal authority. - Seal reserve, share-supply, and payout state before
burnHookor any other strategy callback can run. The invariant to write down is notburn finishes correctly; it isafter every callback edge, no nested burn can still redeem the same WETH-side inventory again. - Separate flexible strategy bookkeeping from live custody math. If a hook only exists to update strategy-side state, it should run after vault-side burn accounting is already final or receive only pre-committed, non-authoritative data.
- Model one-real-asset / one-worthless-asset pool creation explicitly in tests and reviews. If an attacker can fabricate one leg of the pair, the protocol must still prove that LP mint/burn cannot overpay the money-good side.
- Apply reentrancy controls at the full mint/burn lifecycle boundary, not only around one internal helper. The dangerous question is whether any nested call can still observe reserve truth that an in-flight withdrawal is already spending.
- Make plugin execution inventory-scoped. A strategy callback should never inherit ambient approval, vault balances, or reserve-accounting authority broader than the exact asset delta already committed for that step.
- Re-run security review whenever post-audit product changes expand hook reachability, strategy mutability, or user-controlled endpoint admission.
Audited interfaceis not the same thing asaudited live trust boundary.
Audit prompts
- Which exact reserve, share, and payout variables are still authoritative when
burnHookfires, and could a nested call spend them twice? - Is
strategybeing authenticated assafe code to run on a withdrawal boundary, or merely asa contract that implements the expected ABI? - Can a user-created pool pair one real asset with one attacker-fabricated asset and still obtain LP claims that the vault will honor against the real side during burn?
- If strategy code re-enters
burn,mint,rebalance, or any sibling helper, what object proves the outer frame has already consumed its withdrawal right? - Does the protocol expose any ambient approvals, vault inventory, or temporary capability bits to plugin code that are broader than the single step being executed?
- Which product or deployment changes occurred after audit, and did any of them widen strategy admission, hook timing, or burn-path authority without a fresh hostile-plugin review?
- Could the same architecture fail even with a
nonReentrantmodifier if strategy callbacks still inherit too much pre-committed inventory or stale reserve truth through another path?
Lessons that should already be standard
- User-extensible strategy systems are custody systems the moment they run during mint, burn, or rebalance.
Pluginis a product word, not a trust-boundary exemption. - Interface conformance is not behavioral trust. A contract satisfying
burnHook(...)says nothing about whether it is safe to call before reserves and payouts are final. - A fake asset leg is often enough. If exit math can overpay the real side, the attacker does not need a second money-good asset to make the exploit economic.
- Reentrancy review has to follow authority, not just function names. The important question is which in-flight withdrawal object stays spendable across the callback, not whether one helper remembered to add a guard.
- Post-audit hook-surface drift is itself a recurring exploit class. Teams keep shipping architectures that were reviewed as static integrations and later become user-programmable reserve boundaries.
- The healthy design target is stronger than
strategy can’t do anything too weird: strategy execution should never inherit reserve-bearing authority broad enough to turn one honest LP burn into two withdrawals.
Internal linkages
- Core recurring pattern: reentrancy.
- Frame-authenticity lens: callback-frame-authority-reuse — the outer burn left a still-live withdrawal context around pool reserves, and
burnHooklet attacker code spend that context again before the first frame fully closed. - Admission / endpoint-semantics companion: interface-conformance-semantic-compatibility-failure — Clober did not just call out to
some strategy; it treated a caller-supplied strategy ABI as if that were enough proof the endpoint was safe to run on the burn boundary of a reserve-bearing vault. - Architecture companion: privilege-stripped-external-execution-and-inventory-scoped-trampolines — the healthier design answer is not
let arbitrary strategy code run from the vault during burn; it isseparate privileged vault accounting from any flexible external logic and inventory-scope whatever plugin execution remains. - Useful comparison: penpie-malicious-pendle-market-batchharvestmarketrewards-reentrancy-2024-09-03 — both incidents let an attacker-controlled integration endpoint satisfy local interface expectations and then turn a hook/callback into a live theft path.
- Useful vault-side contrast: grim-finance-spirit-lp-vault-reentrancy-2021-12-18 — Grim also turned an attacker-controlled asset boundary into share-accounting theft, but through deposit-side token callbacks rather than burn-side strategy hooks.
Control surface
-
The decisive leverage sat in Clober’s pool-creation permissioning, the decision to accept arbitrary strategy contracts, the
burnHookcallback during LP withdrawal, and the incomplete sealing of reserve/accounting state before attacker-controlled code regained execution. -
The protocol did not mainly fail because reentrancy is mysterious. It failed because an attacker-controlled strategy was allowed to sit directly inside the burn path of a reserve-bearing vault.
-
The deeper review question is architectural: if a pool-specific plugin can run during mint or burn, what exact inventory does it see, what exact authority does it inherit, and what prevents that callback from reusing the vault’s withdrawal frame before reserves are finalized?
-
Sources:
- https://rekt.news/cloberdex-rekt
- https://www.certik.com/blog/clober-dex-incident-analysis
- https://blog.solidityscan.com/cloberdex-liquidity-vault-hack-analysis-f22eb960aa6f/
- https://www.quillaudits.com/blog/hack-analysis/cloberdex-reentrancy-exploit-501k
- https://basescan.org/tx/0x8fcdfcded45100437ff94801090355f2f689941dca75de9a702e01670f361c04
- https://basescan.org/address/0x6A0b87D6b74F7D5C92722F6a11714DBeDa9F3895#code
-
Last reviewed: 2026-07-20 UTC