Cork Protocol weETH-DS-as-RA + unauthenticated CorkHook beforeSwap() cross-market redemption drain (2025-05-28)
- Name: Cork Protocol weETH-DS-as-RA + unauthenticated CorkHook
beforeSwap()cross-market redemption drain - Date: 2025-05-28
- Protocol: Cork Protocol
- Chain: Ethereum
- Category: market-role substitution / account confusion / unauthenticated hook callback / cross-market redemption drain
- Loss: about
3,761.878 wstETH; roughly$11M-$12M - Summary: Cork’s EtherFi
wstETH:weETHmarket was drained after the attacker combined two independent flaws. First, a near-expiry rollover / risk-premium miscalculation let them turn about0.0000029 wstETHinto roughly3,760.8813 weETH-CTin the legitimate market. Second, Cork let a new market treat the legitimate market’sweETH-DStoken as its own Redemption Asset (RA) and exposedCorkHook.beforeSwap()without proving the call came from the canonical Uniswap v4 PoolManager / pool context. With a malicious market and crafted hook data, the attacker made Cork credit about3,761realweETH-DSinto the new market as if they had deposited them there, minting freshCT + DSon the attacker side. They then redeemed those fake-market claims back into the realweETH-DS, paired them with the cheaply acquired legitimate-marketweETH-CT, and exercised the original market’sCT + DS = RAredemption path to withdraw about3,761.878 wstETH, which they later swapped into about4,530 ETH. - Trigger / entry point:
- The decisive exploit transaction was
0xfd89cdd0be468a564dd525b222b728386d7c6780cf7b2f90d2b54493be09f64d. - Cork allowed permissionless market creation with arbitrary Redemption Asset (
RA) and Pegged Asset (PA) choices, so the attacker could create a new market using the legitimate market’sweETH8DS-2token as the new market’sRA. - The new market used attacker-controlled exchange-rate / hook infrastructure centered on contract
0x9Af3dCE0813FD7428c47F57A39da2F6Dd7C9bb09. - Cork’s Uniswap v4 hook surface, especially
beforeSwap(), did not reliably provemsg.sender, pool id, and hook context were the canonical Cork-controlled ones before honoring hook data that triggered Cork-side settlement logic. - Public reconstruction also showed the attacker could stand up a sibling Uniswap v4 pool over the same economically relevant tokens but with an attacker-controlled hook, then feed that pool identity into Cork’s hook-driven settlement path.
- Cork’s token-role validation was too weak: interface-compatible or expiry-bearing tokens from one market could be admitted into another market in the wrong economic role.
- The decisive exploit transaction was
- Root cause:
- Cork authenticated the wrong root objects. It let the attacker define a new market whose
RAwas actually a derivative token (weETH-DS) from another market rather than a canonical redemption asset for the new market. - Cork also authenticated the wrong callback context.
beforeSwap()could be reached with attacker-shaped pool / hook data instead of only from the exact Uniswap v4 manager and pool Cork meant to trust. - A separate rollover / risk-premium edge near expiry let the attacker cheaply acquire the legitimate market’s
weETH-CT, which became the matching half needed for final redemption in the original market. - In short: Cork let one market’s derivative token masquerade as another market’s reserve asset, then let unauthenticated hook context mint claims against that counterfeit setup, and finally still honored the original market’s real redemption path.
- Cork authenticated the wrong root objects. It let the attacker define a new market whose
- Exploit path:
- The attacker first targeted the legitimate EtherFi Cork market whose key token roles were broadly:
RA = wstETH,PA = weETH,DS = weETH8DS-2, andCT = weETH8CT-2. - Near expiry, they exploited Cork’s rollover / risk-premium calculation so a tiny amount of
wstETHcould be transformed into roughly3,760.8813 weETH-CTin the legitimate market. Dedaub describes this as a skewedCT:RAratio carried into the next maturity rollover. - The attacker then created a new malicious Cork market whose
RAwas the legitimate market’sweETH8DS-2, whosePAwaswstETH, and whose fresh derivative pair waswstETH5CT-3/wstETH5DS-3. - They seeded that malicious market / Uniswap v4 pool with a tiny amount of
weETH8DS-2so the pool could initialize, then also created a sibling same-token pool whose distinguishing feature was the attacker-controlled hook contract rather than a canonical Cork hook binding. - During the main exploit transaction, they used a crafted unlock flow against Uniswap v4’s PoolManager and drove Cork’s
beforeSwap()logic with attacker-shaped pool / hook data instead of only through a fully authenticated canonical Cork pool callback. - Because Cork did not bind the flow tightly enough to the canonical PoolManager + pool id + hook combination, the supplied hook data was interpreted as a legitimate
RAdeposit path for the malicious market. - Cork then treated the crafted flow as if about
3,761 weETH8DS-2had been deposited asRAinto the malicious market, minting corresponding fake-marketCT + DSto the attacker even though thoseRAtokens were not legitimately deposited along the intended path. - The attacker redeemed the fake-market
CT + DSthrough Cork’s normal logic to withdraw the realweETH8DS-2now sitting inside the malicious market. - They combined those recovered legitimate-market
weETH8DS-2tokens with the cheaply acquired legitimate-marketweETH8CT-2from step 2. - Using the original market’s intended
CT + DS = RAredemption path, they redeemed those paired tokens for about3,761.878 wstETHfrom the legitimate market. - They later swapped the stolen
wstETHinto about4,530 ETH, leaving the real market drained.
- The attacker first targeted the legitimate EtherFi Cork market whose key token roles were broadly:
- What the attacker needed to be true:
- Cork had to allow permissionless market creation without enforcing that
RAin a new market was a canonical redemption asset rather than another Cork derivative token from a different market. - The hook / settlement path had to accept attacker-shaped callback context instead of proving it came from the exact PoolManager and exact Cork-approved pool.
- The protocol had to keep token state sufficiently pooled or reusable across markets that one market’s derivative token could become another market’s economically meaningful input.
- The legitimate market still had to honor
CT + DS = RAredemption at par once the attacker assembled both halves. - The near-expiry rollover path had to let the attacker obtain the legitimate market’s
CTside almost for free, otherwise the cross-market fake-RA maneuver would not have cashed out through the original market.
- Cork had to allow permissionless market creation without enforcing that
- Technical anatomy worth remembering:
- This was not just a Uniswap v4 hook bug and not just a token-type bug. The exploit needed both: counterfeit market role assignment plus unauthenticated hook-driven settlement.
- The fake market did not directly pay out
wstETH. It first turned a real market’sDStoken into the malicious market’s apparentRA, then used Cork’s own mint / redeem machinery to extract thatDS, and only then paired it with legitimate-marketCTto drain the original market’s true reserves. - The rollover / risk-premium flaw mattered because it supplied the missing half of the original market’s redemption equation. Without the cheap
weETH-CT, the forged access toweETH-DSwould have been less directly monetizable. - Dedaub’s reconstruction is especially useful because it localizes several distinct control-surface misses:
beforeSwap()lacked the equivalent of strict PoolManager-only gating, Cork did not bind settlement tightly enough to an approved pool id / hook pairing, and market initialization logic validated expiry-bearing token shape more than market-local economic role. - The public writeups also highlight a same-token / different-hook ambiguity: the attacker could create a pool over the relevant tokens whose difference from the legitimate pool was the hook contract, then rely on Cork not to treat that hook identity mismatch as fatal.
- Cork’s permissionless market-creation ambition sharply expanded its trust boundary: token role, hook caller, pool identity, and cross-market state segregation all became part of one security object, but the implementation did not keep them bound together.
- This is a strong example of how
interface-compatible tokenis not the same thing aseconomically valid token role. A DS token from one market may be a perfectly real ERC-20 and still be invalid as RA in another market. - It is also a good singleton-design warning: once balances and economically meaningful tokens from multiple markets coexist inside shared machinery, a bug in a freshly created market can become an extraction path against an older healthier market if cross-market role boundaries are soft.
- Representative transactions and addresses:
- Main exploit tx:
0xfd89cdd0be468a564dd525b222b728386d7c6780cf7b2f90d2b54493be09f64d - Example legitimate mint / split tx cited in Dedaub analysis:
0xc5f5f1cfa0e572684c2d345abadb930625251fafc556dc2f45b6985aeecd9f29 - Attacker EOA:
0xEA6f30e360192bae715599E15e2F765B49E4da98 - Attacker market / rate-provider / hook contract:
0x9Af3dCE0813FD7428c47F57A39da2F6Dd7C9bb09 - Victim Cork contract cited in public analysis:
0xCCd90F6435dd78C4ECCED1FA4db0D7242548a2a9 - Router contract holding real-market DS during public reconstructions:
0x55B90B37416DC0Bd936045A8110d1aF3B6Bf0fc3 - Uniswap v4 PoolManager:
0x000000000004444c5dc75cb358380d2e3de08a90 - Fake-market CT token:
0x51f70fe94e7ccd9f2efe45a4f2ea3a7ae0c62f8c - Fake-market DS token:
0x1d2724ca345e1889cecddefa5f8f83666a442c86
- Main exploit tx:
- Response / mitigation:
- Cork paused protocol activity immediately after the exploit and later published a post-mortem stating that about
3,761 wstETHhad been extracted from the affected liquidity vault. - Public post-mortems converged on several required fixes: authenticate all Uniswap v4 hook entrypoints strictly to the PoolManager and approved pool ids, forbid cross-role token substitution when new markets are created, and tighten market-creation rules around what may serve as
RA. - The incident also underscored the audit-boundary problem around hook-heavy architectures: multiple audits existed, but the decisive hook contracts and cross-component invariants were not all reviewed together deeply enough.
- Cork paused protocol activity immediately after the exploit and later published a post-mortem stating that about
Pattern tags
- account-confusion-root-of-trust-substitution
- callback-origin-authentication-failure
- market-role-authenticity-and-cross-market-token-segregation
- settlement-envelope-truth-security-object
Why the exploit worked
- Cork let the attacker pick the wrong economic root object first: a legitimate market’s
DStoken could become the apparentRAfor a new market without crossing a hard role-admission boundary. - Cork then let hook-driven settlement trust the wrong execution context:
beforeSwap()logic consumed attacker-shaped pool / hook information strongly enough to credit a fakeRAdeposit path. - The protocol’s shared / singleton-style market machinery meant the fake market did not have to be valuable on its own; it only had to manufacture a path to recover real
weETH-DSthat still mattered to the legitimate market. - The near-expiry rollover bug supplied the other half of the redemption equation by making legitimate-market
weETH-CTalmost free, so the forged access toweETH-DScould immediately cash out through the realCT + DS = RApath.
Detection and audit pivots
- Reconstruct the exact market-role graph at market creation: which tokens are allowed to be
RA,PA,CT, andDS, and what concrete rule forbids one market’s derivative from becoming another market’s reserve asset? - Re-audit every external hook entrypoint, not just
unlockCallback(): what exactly proves the caller is the canonical PoolManager, that the pool id is approved, and that the hook contract bound to that pool is the one the protocol intended? - Search for same-token / different-hook ambiguity. If an attacker can create a sibling pool over the same pair but swap in a different hook, does any downstream settlement path still treat that pool as authoritative enough to move value?
- Trace whether helper / hook data can ask Cork to credit deposits, mint claims, or settle balances without the corresponding canonical asset movement being independently proven.
- Inventory cross-market singleton exposure explicitly: if a newly created market is compromised, which pre-existing market-local tokens or reserves can its settlement paths still touch?
- Treat near-expiry rollover logic as security-critical when those ratios determine how much of one side of a paired redemption equation an attacker can synthesize almost for free.
Failure-prevention checklist
- Bind market creation to explicit role-admission rules: a token should not become
RAmerely because it is a real ERC-20 with expiry-like metadata or interface compatibility. - Authenticate every economically relevant Uniswap v4 hook callback to the exact PoolManager, approved pool id, and expected hook identity before any settlement-like side effect occurs.
- Keep same-token pools with different hook contracts economically segregated unless the protocol has one explicit rule saying they are equivalent.
- Make deposit-crediting paths prove asset movement, not just hook-data shape. If the protocol mints
CT + DS, it should be able to point to the exact canonicalRAtransfer or custody delta that justified the mint. - Treat market-issued derivatives as market-local by default. Cross-market reuse as reserve, repay, or payout truth should require a separate admission decision, not happen implicitly through transferability.
- Reuse the same invariant across hook, helper, and direct entrypoints so
main path secure, convenience path loosercannot become a settlement bypass. - Put route-local blast-radius controls under new markets and new hooks: isolated payout buckets, delayed activation, caps, and fast pauses should survive one bad market-role admission.
- Review rollover / maturity migration math as part of the same security object when it can cheaply manufacture one half of a later reserve-redemption equation.
Audit prompts
- What exact market-creation rule prevents one market’s
CTorDStoken from being admitted as another market’sRA, and where is that rule enforced onchain rather than in docs? - Which exact tuple authenticates hook context before Cork-side settlement runs:
msg.sender, PoolManager address, pool id, hook contract, token pair, market id, or some tighter bundle? - Can a same-token / different-hook sibling pool ever reach a code path that Cork treats as economically equivalent to the canonical pool for deposit crediting or redemption settlement?
- When Cork credits an
RAdeposit and mintsCT + DS, what exact asset transfer or custody delta proves that the credited reserve really entered the intended market? - What shared router, singleton, or storage paths let a freshly created market touch balances or economically meaningful tokens from an older legitimate market?
- Are hook callbacks other than the most obvious
unlockCallback()path capable of moving value or updating settlement state, and were they all reviewed under the same origin-authentication assumptions? - Could a rollover, maturity migration, or near-expiry pricing edge cheaply synthesize one side of a redemption equation that becomes dangerous only after a separate role-identity or hook-authentication failure?
- If a market is permissionlessly created today, what caps, quarantines, or payout segregation stop it from immediately becoming a drain path against older markets if role admission is wrong?
Lessons that should already be standard
- A token being real, transferable, and interface-compatible does not make it economically valid for every role in every market.
- In hook-heavy systems, pool identity, hook identity, market identity, and token-role identity need to stay bound together. Authenticating only one or two of them is not enough.
- Permissionless market creation massively widens the trust boundary. If role admission is soft, every new market becomes a potential counterfeit state factory.
- Shared or singleton-style market machinery turns local admission mistakes into cross-market solvency risk. Isolation is not optional once markets can hold each other’s economically meaningful tokens.
- Near-expiry pricing bugs become much more dangerous when the protocol’s redemption equations are composable across markets. Small arithmetic edges can become full drains when paired with identity confusion.
- Uniswap v4 flexibility is power, not safety. Without strict callback authentication and route binding,
custom hookbecomes a clean way to manufacture protocol-authored lies.
Why this incident matters
- Cork preserves a useful modern failure class for the corpus: a permissionless derivatives protocol let one market’s derivative token masquerade as another market’s reserve asset, then let an unauthenticated hook path operationalize that fiction into redeemable claims.
- It is a strong exemplar of account confusion on the EVM side, not because the fake object was a trivial mock contract, but because the wrong economic root object (
DSasRA) was admitted and then trusted through later settlement logic. - It is also one of the clearest warnings in the Uniswap v4 hook era that hook caller identity, pool identity, and token-role identity must all be authenticated together. Flexibility without those bindings becomes composable counterfeit state.
Internal linkages
- Core recurring pattern: account-confusion-root-of-trust-substitution.
- Adjacent pattern: callback-origin-authentication-failure — the fake market still needed Cork to trust an attacker-shaped hook / pool context before settlement-like logic ran.
- Adjacent pattern: interface-conformance-semantic-compatibility-failure — the protocol accepted a token that was interface-valid and expiry-bearing but economically invalid for the role it was assigned.
Control surface
-
The decisive leverage sat in permissionless market creation, token-role admission (
DSaccepted asRA),CorkHook.beforeSwap()caller / pool authentication, cross-market token segregation, and the rollover pricing path that cheaply supplied the legitimate market’sCThalf. -
Cork did not mainly fail because one arithmetic line was wrong. It failed because market-role identity, hook-origin identity, and redemption semantics stopped referring to the same security object.
-
Sources:
- https://www.cork.tech/blog/post-mortem
- https://dedaub.com/blog/the-11m-cork-protocol-hack-a-critical-lesson-in-uniswap-v4-hook-security/
- https://slowmist.medium.com/exploit-analysis-cork-protocol-attacked-over-10-million-lost-75de9f229307
- https://www.quillaudits.com/blog/hack-analysis/cork-protocol-hack-explained
- https://rekt.news/after-post-mortem
-
Last reviewed: 2026-07-27 UTC