Tech Deep Dive
Dedaub Logo
Dedaub
30 May 2025

The $11M Cork Protocol Hack: A Critical Lesson in Uniswap V4 Hook Security

On 28th of May 2025, Cork Protocol suffered an $11M exploit due multiple security weaknesses, culminating in a critical access control vulnerability in their Uniswap V4 hook implementation. The attacker exploited i) missing validation in the hook’s callback functions, and, ii) the Cork design choice of comingling tokens from multiple markets. This allowed the attacker to orchestrate one of the most sophisticated attacks we’ve seen involving a new “fake” market with manipulated pool states, which confuses the protocol into depositing its own tokens at an unfavorable rate, resulting in lost funds.This incident highlights the importance of proper access control in Uniswap V4 hooks and the risks of highly flexible open designs, which are very hard to secure.

Background: Understanding Cork Protocol

Cork Protocol is a depeg insurance platform built on Uniswap V4 that allows users to hedge against stablecoin or liquid staking token depegs. The protocol operates with four token types per market:

  • RA (Redemption Asset): The “original” asset (e.g., wstETH)
  • PA (Pegged Asset): The “riskier” pegged asset (e.g., weETH)
  • DS (Depeg Swap): Insurance token that pays out if PA depegs from RA
  • CT (Cover Token): The counter-position that earns yield but loses value if depeg occurs

Another way to think of the DS is a put option at a fixed strike price denominated in RA, while CT is the corresponding short put.

Users can mint DS + CT by depositing RA, effectively splitting the redemption asset into two complementary positions. Unlike modern options protocols such as Opyn, the DS is fully collateralized with RA, which simplifies trust assumptions.

(This design is not the most capital efficient way to design an insurance/option protocol, but this is a discussion for another day.)

The Main Vulnerability: Missing Access Control

The first vulnerability lies in the CorkHook contract’s hook callback functions. In the transaction that exploited the protocol, these were called by the attacker’s smart contract directly, mid-transaction. Let’s examine the vulnerable beforeSwap function:

function beforeSwap(
	address sender,
	PoolKey calldata key,
	IPoolManager.SwapParams calldata params,
	bytes calldata hookData
) external override returns (bytes4, BeforeSwapDelta delta, uint24) {
	PoolState storage self = pool[toAmmId(Currency.unwrap(key.currency0), Currency.unwrap(key.currency1))];
	// kinda packed, avoid stack too deep 
	delta = toBeforeSwapDelta(-int128(params.amountSpecified), int128(_beforeSwap(self, params, hookData, sender)));
	// TODO: do we really need to specify the fee here?
	return (this.beforeSwap.selector, delta, 0);
}

Critical Issue: This function lacks an onlyPoolManager modifier (allowing only calls from a trusted Uniswap v4 calls), meaning anyone can call it directly with arbitrary parameters. While the contract inherits from BaseHook which provides access control for unlockCallback, it fails to protect other hook callbacks.

// BaseHook provides this for unlockCallback: 
modifier onlyPoolManager() {
	require(msg.sender == address(poolManager), "Caller not pool manager"); _;
}

The Attack Vector

Cork Protocol allowed DS tokens from one market to be used as RA tokens in another market. This was likely not an intentional design choice, and the protocol authors probably didn’t think of this possibility. An unintentional consequence of this is that relatively valuable tokens (DS tokens) from a good market can potentially be accessed from another market if there’s a vulnerability.

The attacker exploited this vulnerability through a sophisticated multi-step attack.

STEP 1: CROSS-MARKET TOKEN CONFUSION

The attacker created a malicious market configuration that used one of the DS token in another market as an RA token in the new market.

// Legitimate market
Legit Market: {
	RA: wstETH,
	PA: weETH,
	DS: weETH-DS,
	CT: weETH-CT
}
// Attacker's malicious market 

Fake Market: { 
	RA: weETH-DS, // Using DS token as RA!
	PA: wstETH,
	DS: new_ds,
	CT: new_ct
}

Step 2: Malicious Hook Contract

The attacker deployed their own contract implementing the hook interface and rate provider interface.

The new market utilized a freshly created Uniswap v4 pool that utilized the attacker’s contract as the Hook!

Step 3: Direct Hook Manipulation

Due to the missing access control, the attacker could directly call beforeSwap to manipulate pool states:

Step 4: Token Extraction

Through careful manipulation of the pool reserves and swap parameters, the attacker was able to:

  1. Deposit minimal new_ct tokens while receiving disproportionate new_ds tokens
  2. Use new_ds + new_ct to redeem weETH-DS tokens
  3. Combine weETH-DS with legitimately purchased weETH-CT to redeem $11m of wstETH

Technical Deep Dive: Hook Manipulation

The _beforeSwap function contains complex logic for handling swaps, including reserve updates and fee calculations:

function _beforeSwap(
  PoolState storage self,
  IPoolManager.SwapParams calldata params,
  bytes calldata hookData,
  address sender
) internal returns (int256 unspecificiedAmount) {
    // ... swap calculations ...
    // Update reserves without validation
    self.updateReservesAsNative(Currency.unwrap(output), amountOut, true);
    // Settle tokens
    settleNormalized(output, poolManager, address(this), amountOut, true);
    // ... more logic ...
}

Without access control, an attacker can:

  • Manipulate reserve ratios before legitimate trades
  • Force the hook to settle tokens with arbitrary amounts
  • Bypass normal swap routing through the PoolManager

Contributing Factors

1. Arbitrary Market Creation

The protocol allowed anyone to create markets with any token pair:

function beforeInitialize(address, PoolKey calldata key, uint160) external ... {
    address token0 = Currency.unwrap(key.currency0);
    address token1 = Currency.unwrap(key.currency1);
    
    // Dedaub: No validation on token types!
    // Allows DS tokens to be used as RA tokens

}

2. Insufficient Token Validation

The _saveIssuedAndMaturationTime function attempts to validate tokens but fails to ensure proper token types:

function _saveIssuedAndMaturationTime(PoolState storage self) internal {
    IExpiry token0 = IExpiry(self.token0);
    IExpiry token1 = IExpiry(self.token1);
    // Dedaub: Only checks if tokens have expiry, not their type
    try token0.issuedAt() returns (uint256 issuedAt0) {
        self.startTimestamp = issuedAt0;
        self.endTimestamp = token0.expiry();
        return;
    } catch {}
    // ... similar for token1 ...
}

Lessons Learned

1. Always Implement Access Control on Hook Callbacks

Every hook callback that can modify state MUST verify the caller:

2. Validate Token Types, especially if your protocol allows New Market Creation

3. Implement Pool Whitelisting

For hooks handling valuable assets, consider restricting which pools can use the hook.

mapping(PoolId => bool) public allowedPools;

modifier onlyAllowedPool(PoolKey calldata key) {
    require(allowedPools[key.toId()], "Pool not allowed");
    _;
}

4. ADOPT DESIGNS WERE TOKENS FROM MULTIPLE MARKETS DO NOT COMINGLE

A vulnerability that may apply to one market shouldn’t be able to extract tokens on all markets.

Previous Cork Protocol Audits

It is so unfortunate that although the Cork protocol had undergone security reviews by four different audit providers, this incident still happened. The protocol team had clearly invested resources in security, making this exploit all the more tragic for both the team and users.

However, among the four auditors, only Cantina/Spearbit appears to have had the vulnerable CorkHook contract within their audit scope. Their pull request with recommendations shows they did identify some issues and suggested improvements, even to the CorkHook contract.

Runtime Verification, another auditor, did not have CorkHook in their scope but presciently noted in their report:

“An interesting follow-up engagement would be to prove the invariants for the CorkHook functions that are being invoked by different components verified within the scope of this engagement, as well as the functions of other contracts, such as CorkHook, Liquidator and HedgeUnit.”

This observation now seems particularly prophetic, as it was precisely the CorkHook’s interaction with other components that enabled the exploit.

The complexity of modern DeFi protocols, especially those integrating with complex systems like Uniswap V4, presents unique challenges for security reviews. In such cases we recommend that rather than splitting a project into small pieces and auditing components individually, to instead utilize highly expert providers on the entire codebase. The Cork team’s commitment to security through multiple audits makes this exploit particularly heartbreaking, and highlights how even well-intentioned security efforts can fall short in the face of increasingly sophisticated attack vectors.

Recommendations for Hook Developers

  1. Inherit from BaseHook: Always use the provided base contracts that include security checks
  2. Implement Comprehensive Access Control: Every external function should validate its caller
  3. Validate All Inputs: Never trust external input, especially token addresses and amounts
  4. Conduct Thorough Audits: Hook contracts require specialized security reviews due to their unique attack surface

Finally, if you’re building on Uniswap v4, get your code audited by experts. Dedaub is Uniswap-whitelisted audit provider. This means that you can get your code audited by our team, with world-leading security experts in Uniswap and DeFi. The audit can also be paid for via a Uniswap Foundation grant.

Conclusion

The Cork Protocol hack demonstrates that Uniswap V4 hooks, while powerful, introduce new security considerations that developers must carefully address. The combination of missing access controls and insufficient token validation created a perfect storm for exploitation. As the DeFi ecosystem continues to evolve with more composable protocols, developers must prioritize security at every layer of their architecture.