The Notorious Bug Digest #5: Breaking EIP-7702 Assumptions, JIT Penalty Bypass & Recursive Function Exploit Explained

The Notorious Bug Digest #5: Breaking EIP-7702 Assumptions, JIT Penalty Bypass & Recursive Function Exploit Explained

Source: The Notorious Bug Digest #5 – OpenZeppelin


Overview

OpenZeppelin’s latest bug digest reveals three critical Web3 security findings, dissecting complex incidents that expose emerging risks in the post-EIP-7702 era, Uniswap V4’s penalty mechanism, and recursive function pitfalls in DeFi protocols.


1. EIP-7702 Delegated EOA Exploit Circumvents Flashloan Protection

Background: EIP-7702 enables EOAs (Externally Owned Accounts) to run delegated code inside their accounts, fundamentally changing assumptions in smart contracts which relied on msg.sender == tx.origin to ensure callers were EOAs, not contracts.

Exploit Summary:

An attacker exploited this by:

  • Deploying a malicious delegated contract assigned to an EOA.
  • Transferring ~13.9 BNB to trigger the delegated contract’s fallback function, fooling the victim staking contract into thinking it was a simple EOA call.
  • Flashloaning $3.5M BSC-USD, inflating POT token price via Uniswap V2 pool manipulation.
  • Staking ~220k POT tokens at the inflated price, causing the victim contract to record an inflated stake value.
  • Repaying the flashloan, deflating POT price but locking in profit.
  • Later, immediately unstaking a manipulated position, yielding 3.3M POT tokens-far exceeding the original stake.

The attacker carefully timed staking and unstaking to bypass a mandatory 1-day delay, pocketing $85,000. This represents one of the first major exploits leveraging the breakdown of EOA-only guarantees after EIP-7702.

Image A - Stake Function
Image B - On-chain Price Fetch
Image C - Malicious Delegated EOA Call
Image D - Attack Steps
Image E - Unstake Function

Key Takeaway: Contracts relying on msg.sender == tx.origin for security must revisit these checks as post-EIP-7702 EOAs can behave like contracts, enabling dangerous bypasses.


2. Uniswap V4’s JIT Liquidity Penalty Can Be Exploited When Attacker Controls Penalty Recipient

Uniswap V4’s penalty is designed to deter instant liquidity providers (JIT LPs) by forfeiting fees if liquidity is removed too quickly; the penalty is donated to LPs within the current tick range.

Vulnerability: If the attacker controls the LP delivering the “donation,” they effectively receive their own penalty back, nullifying deterrence.

Attack Flow:

  • Secondary account provides liquidity in a rarely-used tick.
  • Main account adds temporary large liquidity near the active tick and earns fees.
  • After the swap, moves pool price into secondary account’s tick.
  • Removes liquidity, triggering penalties donated to the attacker’s own tick.
  • Swaps again to restore the pool price.

Though theoretically sound, practical success is limited to low-liquidity pools due to high costs of price manipulation and timing.

Image F - afterRemoveLiquidity() Hook

Lesson: Penalty mechanisms distributing funds to in-range positions must prevent attackers from controlling donation recipients to avoid “penalty rebates.”


3. Recursive Function Bug Locks User Funds in the f(x) Protocol

The f(x) Protocol manages leveraged long positions with a complex “tick-tree” structure organizing positions by risk bands. Partial liquidations rebalance nodes along this tree recursively.

Bug Details:

  • A recursive function _getRootNodeAndCompress() updates nodes but fails (stack overflow) with ~150+ child nodes.
  • Missing minimum liquidation size allowed attackers to perform many minimal partial liquidations, creating large trees with excessive child nodes.
  • The redeem function, used during extreme conditions, could be abused to generate this node bloat.
  • Positions attached to these oversized node trees cannot be updated or closed, effectively locking users’ funds.
Image G - Tick-Tree Structure
Image H - Liquidation And Rebalancing Scenario
Image I - Recursive getRootNodeAndCompress() Function
Image J - Child Node Attached on the Same Tick
Image K - Internal _liquidateTick() Function
Image L - Tree Structure After Manipulation

Mitigations:

  • Replaced the recursion with an iterative version of the node compression function.
  • Added minimum debt thresholds for redemption, rebalancing, and liquidation.
  • Ensured tick movement validation during redemption.
  • Enabled off-chain monitoring and admin-triggered node compression.

Insight: Recursive functions in critical financial logic demand robust safeguards against stack overflow and resource exhaustion attacks.


Final Thoughts

These vulnerabilities underscore the evolving complexity of Web3 contracts post-EIP-7702, challenges in DeFi automated protections, and risks in recursive logic.

Developers and auditors must:

  • Reconsider legacy security assumptions impacted by protocol upgrades.
  • Carefully assess penalty and reward flows for exploitable loops.
  • Avoid deep recursion or implement iterative mechanisms for critical paths.
  • Enforce strict limits on partial liquidation thresholds.

OpenZeppelin’s deep dive provides valuable lessons to help the community shore up defenses against subtle but impactful exploit vectors.