
Building secure Uniswap v4 hooks
Trail of Bits distills dozens of Uniswap v4 hook audit findings into seven recurring failure patterns — missing caller checks, unvalidated PoolKey trust, custom accounting leaks, wrong-hook timing bugs, permission-bit mismatches, callback-triggered denial of service, and cross-callback state changes. The post walks through real incidents (the ~$12M Cork exploit and $8.4M Bunni rounding bug) to show how these bugs bypass PoolManager's settlement invariant, and gives developers and auditors a concrete checklist plus fuzzing guidance (Echidna, Medusa) for securing hook contracts.
What it is
A Trail of Bits engineering post cataloguing recurring security failures in application and hook code built on Uniswap v4. The existing summary names the incidents and the categories; what follows is the concrete defensive guidance the summary cannot carry — the specific fixes, the trust boundary, and the accounting invariants to test.
The trust boundary
The PoolManager enforces only protocol mechanics: pool init rules, swap/liquidity math, hook-callback sequencing, and end-of-session settlement (via unlock() → callback → check no unsettled deltas remain). Everything application-specific — who may call privileged paths, which pools are legitimate, custom delta accounting, safe external calls — is the hook developer's responsibility. Critically, settlement only verifies the session's currency deltas resolve; it does not validate a hook's internal accounting, so a hook can leak value while settlement still succeeds.
flowchart TD
A[Attacker input] --> B{Caller checked?}
B -->|No| X[Direct callback / internal action]
A --> C{PoolKey validated?}
C -->|No| Y[Malicious pool: attacker currencies + per-pool data]
D[Hook delta logic] --> E{Accounting correct?}
E -->|Wrong sign/rounding| Z[Value leaks — settlement still passes]What to do
- Caller checks: Use
BaseHookfor hook entrypoints andSafeCallbackforunlockCallback; they enforce caller checks on covered paths. Add an equivalent check only on paths those base contracts don't cover. - Pool legitimacy: Restrict initialization in
beforeInitialize, or bind the hook to canonical pools at deployment / maintain a strict allowlist. Re-derive and re-check thePoolIdon every user-controlled path, since pool creation is permissionless by default and the hook address is part of pool identity. - NoOp / return-delta hooks: If a
BeforeSwapDeltaconsumes the user's entire specified amount, the hook supplies the trade — treat it as a custom AMM and test conservation, price bounds, rounding, and returned deltas against real balances. - Dynamic fees: Bound every fee, rate-limit privileged fee changes, and never derive a fee directly from cheaply manipulable inputs.
- Test these three accounting invariants for value-moving hooks: 1. No user receives output the accounting did not charge for. 2. A same-transaction round trip cannot create value from accounting alone. 3. Internal accounting matches actual asset balances.
- Verify invariants hold for the actual tokens handled — fee-on-transfer tokens can make the amount received smaller than expected. Attacker-chosen ERC-20 currencies (
currency0/currency1) can trigger malicious behavior or reenter mid-flow.
Caveats
The page frames these as a development/audit checklist, not exhaustive coverage — it lists seven patterns but the fetched text cuts off partway through pattern 3. The Cork loss (~$12M, May 2025) required the access-control gap combined with a separate pricing issue; neither Cork nor Bunni stemmed from a flaw in v4 core or the PoolManager itself.
Organisations named here
- Bunni exploit
- Cork exploit
- Sorella Angstrom
Technologies named here
- BaseHook
- Uniswap v4 hooks
- SafeCallback
- Uniswap V4 PoolManager
- Cork protocol
- Echidna
- MEDUSA
- Bunni protocol
- Solodit database
- SVFHook
- Uniswap v4-core security review
- Sorella Angstrom hook
- LiquidityPenaltyHook
- Uniswap v4
- Solidity
- Ethereum
- Trail of Bits
Techniques named here
- Missing caller checks on hook callbacks
- Trusting attacker-created pools
- Custom accounting value leakage
- NoOp swap via return-delta hooks
- Dynamic fee manipulation
- Non-standard token behavior exploitation
- Wrong-hook timing bugs
- Hook address permission bit mismatch
- Proxy upgrade bypassing address permission immutability
- Denial of service via reverting non-essential hook logic
- Denial of service via required external dependency failure
- Cross-callback shared state manipulation / reentrancy
Related in AppSec
Flowise MCP Security Bypass Enables RCE
Inside an Oracle Database SQL Injection Attack | Huntress
OASIS
