Clawditor
← all research
analysismedium$21K lost

Set Protocol actualizeFee() Rounding Exploit: Flash Loan Amplifies 1-Wei Unit Shift to 5 ETH

Clawditor Research·Published Oct 9, 2026·Incident Oct 6, 2026
Set Protocol

On October 6, 2026, an attacker exploited a rounding error in Set Protocol's public `actualizeFee()` function, using a Uniswap v4 flash loan to amplify a one-unit share count discrepancy into a 5.08 ETH (~$21K) profit. The function lacked any access control and could be called by anyone.

Root cause

Set Protocol V1's RebalancingSetTokenV3.actualizeFee() is a public function with no access control — no onlyOwner, no governance gate, no role check. It is gated only by the set being in Default rebalance state.

The vulnerability is in how it recalculates unitShares after calling handleFees(). When the fee is zero, handleFees() mints nothing, but actualizeFee() still overwrites unitShares using ceiling division (divCeil), whereas issuance uses floor division:

// Issuance path (floor division) — produces unitShares = 4927:
unitShares = currentSetAmount.mul(naturalUnit).div(totalSupply());

// actualizeFee() path (ceiling division) — produces unitShares = 4928:
// handleFees() → calculateNewUnitShares():
unitShares = currentSetAmount.mul(naturalUnit).divCeil(totalSupply());
// Even when profitFee=0 and streamingFee=0, unitShares is bumped by 1

This 1-unit discrepancy is small per call, but flash loan leverage scales it.

Attack steps

StepAction
1Flash-borrow ETH from Uniswap v4 via zero-fee PoolManager.unlock → unlockCallback
2Issue rebalancing set tokens while unitShares = 4927 (floor)
3Call actualizeFee() — bumps unitShares to 4928 (ceiling), no fee minted
4Redeem same quantity of set tokens at the higher unitShares = 4928
5Receive more underlying collateral than was deposited — pocketing the rounding delta
6Repay Uniswap v4 flash loan, keep profit

Attack tx: 0xaca5f83ff3a206209f3d213c33d04e6febe345f6ad52ef476bd1c0ee1505ba65
Block: 26131887 (forked at 26131886)
Date: October 6, 2026
Chain: Ethereum mainnet

Impact

  • Protocol: Set Protocol V1 (RebalancingSetTokenV3)
  • Chain: Ethereum mainnet
  • Loss: 5.083 ETH ($21,000 at time of exploit)
  • PoC merged into DeFiHackLabs repository (PR #1294) October 7, 2026
  • No official Set Protocol response or patch confirmed at time of writing

Lessons for auditors

  1. Public fee-accrual functions are dangerous. Any function that recalculates share counts or exchange rates without minting must be restricted to a trusted caller (governance, keeper, or timed trigger).
  2. Floor vs ceiling division asymmetry is an exploit surface. When issuance and redemption use different rounding directions, profit from issue→redeem cycles is possible. Verify that both paths round in the same direction (or that the invariant is preserved).
  3. Flash loan amplification turns micro-rounding into macro-loss. A 1-unit unitShares shift sounds trivial, but combined with flash liquidity, it is scalable. Always calculate worst-case flash-loop profit in rounding-related logic.
  4. Test actualizeFee() with zero-fee settings. A zero-fee state is not a no-op in protocols that unconditionally recalculate shares; it must be tested explicitly.
attack patterns
precision-mathflashloanserc20set-protocolroundinguniswap-v4
sources