LayerZeroFault
wallet security-fixes

Fix: EIP-7702 Set Code Authorization Replay Attacks & Cross-Chain Delegation Front-Running

VV

Written by

Fact-Checked on September 11, 2026

Verified Expert

Fix: EIP-7702 Set Code Authorization Replay Attacks & Cross-Chain Delegation Front-Running

Ethereum’s Prague/Electra upgrade introduced EIP-7702 (Set Code for EOA at Transaction), revolutionizing Account Abstraction by allowing standard Externally Owned Accounts (EOAs) to temporarily delegate their code execution to a smart contract without deploying a separate ERC-4337 smart account contract.

While EIP-7702 solves key onboarding and batching hurdles, improper verification of the authorization signature tuple introduces lethal attack vectors: cross-chain authorization replay, perpetual delegation hijacking, and mempool front-running.

If you are securing decentralized application communications or embedded iframe messaging, also inspect our companion analysis on WalletConnect postMessage Missing event.origin Validation.


Technical Architecture of EIP-7702 (Transaction Type 0x04)

Under EIP-7702, a new transaction envelope type 0x04 is defined. The transaction payload contains a list of authorizations:

$$\text{authorization_list} = [[\text{chain_id}, \text{address}, \text{nonce}, y_parity, r, s], \dots]$$

When the EVM processes an authorization:

  1. The EVM recovers the signer $A$ from the tuple $(y_parity, r, s)$ hashed against keccak256(MAGIC || rlp([chain_id, address, nonce])).
  2. The EVM checks that the signer’s on-chain nonce matches nonce.
  3. If valid, the EVM sets the code of account $A$ to the delegation designator bytecode:

$$\texttt{0xef0100} ,|, \text{address}_{20}$$

Placeholder: EIP-7702 Set Code Execution and Delegation Pointer Lifecycle

Any subsequent calls made to account $A$ during or after the transaction will execute the runtime code deployed at address via a context-preserving delegatecall into the target contract.


Threat Vector 1: Cross-Chain Replay via chain_id = 0

The Vulnerability

EIP-7702 allows chain_id in the authorization tuple to be set to 0 to signify wildcard / multi-chain authorization:

// DANGEROUS PATTERN: Wildcard chain_id authorization
const dangerousAuth = {
  chainId: 0n, // Valid on EVERY EVM chain!
  address: "0xDef1Ca1000000000000000000000000000000000",
  nonce: currentNonce,
};

If an EOA signs this tuple to test batch transactions on Sepolia or a local rollup, any observer extracting the tuple from the public mempool can replay the identical tuple on Ethereum Mainnet, Base, Arbitrum, or Polygon.

If the implementation contract at 0xDef1Ca... on Sepolia does not exist or has different bytecode on Mainnet (or worse, is deployed by an adversary via CREATE2), the attacker gains arbitrary execution privileges over the user’s mainnet wallet.

Mitigation: Strict Chain ID Binding

Never permit client-side signing of chainId = 0 in production dApps or wallet SDKs:

// SECURE PATTERN: Enforce explicit active chain ID
import { getChainId } from 'viem/actions';

async function signEip7702Authorization(client: any, targetDelegate: `0x${string}`) {
  const activeChainId = await client.getChainId();
  if (activeChainId === 0) {
    throw new SecurityError("Wildcard chain_id (0) is strictly disallowed under safety protocol.");
  }

  const nonce = await client.getTransactionCount({ address: client.account.address });

  return await client.signAuthorization({
    contractAddress: targetDelegate,
    chainId: activeChainId,
    nonce: nonce,
  });
}

Threat Vector 2: The “Perpetual Zombie Delegation” Trap

Unlike early drafts where delegation expired at the end of the transaction, EIP-7702 preserves code designations across blocks until explicitly overwritten or revoked.

Placeholder: State Trie Account Code Slot and Revocation Mechanism

If an EOA delegates to an account abstraction implementation (e.g., a modular multisig or session key validator) and later resumes using their wallet as a normal EOA:

  1. The delegation bytecode 0xef0100... remains written in their account code slot.
  2. If the delegated contract implementation contained an unprotected selfdestruct (on legacy chains), uninitialized proxy storage, or an arbitrary execute(address to, uint256 value, bytes data) function without access controls, attackers can drain any native ETH or ERC-20 tokens subsequently sent to that EOA.

Defensive Code: Emergency Revocation Script

To revoke an existing code delegation, an EOA must submit a new Type 0x04 transaction targeting address 0x0:

import { createWalletClient, http } from 'viem';
import { mainnet } from 'viem/chains';

const client = createWalletClient({
  chain: mainnet,
  transport: http(),
});

async function revokeDelegation(account: any) {
  const currentNonce = await client.getTransactionCount({ address: account.address });

  // Target 0x0000000000000000000000000000000000000000 clears the code designator
  const revokeAuth = await client.signAuthorization({
    account,
    contractAddress: '0x0000000000000000000000000000000000000000',
    chainId: mainnet.id,
    nonce: currentNonce,
  });

  const txHash = await client.sendTransaction({
    account,
    to: account.address,
    value: 0n,
    authorizationList: [revokeAuth],
  });

  console.log("Delegation revoked in tx:", txHash);
}

Threat Vector 3: Nonce Invalidation Front-Running

Because an EIP-7702 authorization requires auth.nonce == account.nonce:

  1. If an attacker sees a pending Type 0x04 transaction in the public mempool that they wish to censor or disrupt, they can front-run it by submitting a zero-value transaction with higher priority fee from the victim’s account (if private key is partially leaked) or causing a state clash.
  2. Conversely, if a dApp user signs an authorization tuple and concurrently executes a standard transfer before the bundler submits the authorization, the user’s nonce increments from $N$ to $N+1$, permanently invalidating the signed authorization tuple and causing bundler simulation failures (nonce mismatch).

Developer Best Practice: Atomic Bundling

Bundlers and smart account SDKs must enforce that the transaction initiating the EIP-7702 set code operation is the exact transaction that increments the signer’s nonce:

// Smart Contract Implementation Guard
abstract contract Safe7702Implementation {
    // Prevent uninitialized implementation hijacking
    address private immutable _deployer;

    constructor() {
        _deployer = msg.sender;
    }

    modifier onlySelf() {
        // Under EIP-7702 delegatecall, address(this) is the delegating EOA
        require(msg.sender == address(this), "7702: Caller not self");
        _;
    }
}

Defensive Engineering Audit Summary

RiskExploit MechanismArchitectural Remedy
Cross-Chain ReplaychainId = 0 in authorization tupleDisallow chainId: 0 in client signer modules.
Zombie DelegationUnrevoked bytecode left in EOA code slotAutomate 0x0 address revocation when session terminates.
Mempool Nonce ClashNonce increments prior to bundle miningBroadcast authorizations through private RPC endpoints (e.g. Flashbots Protect).
Direct State HijackDelegate contract missing initializer guardsEnsure delegate implementation uses immutable storage or slot-isolated storage (ERC-7201).

Fact-Checked by Victor Vance, Senior Smart Contract Security Analyst & Node Operator.

Partner Spotlight: Gate.io

Trade Securely on Gate.io

Don't risk your assets on centralized silos or unverified endpoints. Trade securely on Gate.io with deep liquidity and institutional-grade security protocols.

Claim $100 Sign-up Bonus

Official Partner Referral Link

Related Inquiries

What is EIP-7702 and how does code delegation work?

EIP-7702 introduces transaction type 0x04, enabling Externally Owned Accounts (EOAs) to temporarily execute bytecode from a designated smart contract address during transaction execution. The EOA signs an authorization tuple (chain_id, address, nonce, y_parity, r, s) that writes a special delegation designator (0xef0100 ++ address) into the account's code slot.

How does an EIP-7702 authorization signature replay attack occur?

If an EOA signs an authorization tuple with chain_id = 0, that authorization is cryptographically valid across all EVM-compatible chains (Ethereum, Arbitrum, Base, Optimism, BSC). An attacker who observes the authorization payload on a testnet or low-security rollup can replay the authorization on Ethereum mainnet, delegating the user's mainnet EOA to a vulnerable or malicious contract implementation.

How do you revoke an active EIP-7702 delegation designation?

To revoke an EIP-7702 code designation, the account holder must broadcast a new type 0x04 transaction containing an authorization payload where the delegate address is set to the zero address (0x0000000000000000000000000000000000000000), using an incremented account nonce.