LayerZeroFault
wallet security-fixes Updated:

EIP-7702 Authorization Revocation & Zero-Address Code Reset

VV

Written by

Updated:

Technical Guide

To resolve an active or compromised EIP-7702 delegation designation, execute an authorization tuple targeting address(0) signed with your current account nonce. Under EIP-7702 specifications, submitting an authorization tuple where the address field is set to 0x0000000000000000000000000000000000000000 revokes smart code execution delegation, immediately restoring normal externally owned account (EOA) behavior and invalidating any malicious proxy delegate code without needing to burn your private key.

Under Ethereum’s Prague/Electra upgrades, EIP-7702 transforms standard Externally Owned Accounts (EOAs) by allowing them to temporarily or persistently adopt smart contract bytecode. When an EOA signs an authorization tuple, the EVM writes a delegation designator into the account’s state trie:

$$\texttt{code}(A) \leftarrow \texttt{0xef0100} ,|, \text{address}_{20}$$

While this unlocks batching, gas sponsorship, and session keys, it introduces a severe security dilemma: What happens when the delegated smart contract implementation is compromised, upgraded with malicious logic, or turns out to be vulnerable?

Unlike session keys that naturally expire after a predetermined timestamp, an EIP-7702 code designation persists indefinitely until explicitly revoked or updated. Every subsequent transaction sent or received by that EOA will execute through the delegated contract’s fallback logic.

If you are auditing cross-chain replay vectors in authorization tuples, refer to our companion investigation on EIP-7702 Set Code Authorization Replay Attacks & Cross-Chain Delegation Front-Running.


[!TIP] Diagnostic Verification: Inspect and decode raw authorization tuples and UserOperation payloads client-side in our air-gapped /tools/erc4337-calldata-decoder/. Also review our security disclosure on EIP-7702 Delegation Replay Attack Prevention.

The Revocation Mechanism: The Zero Address Rule

The EIP-7702 specification provides a formal mechanism to clear code delegation and return the account to a clean EOA state.

According to the specification:

If the address field in the authorization tuple is 0x0000000000000000000000000000000000000000, the delegation designator is removed, and the account code is reset to empty (0x).

stateDiagram-v2
    [*] --> StandardEOA: Account Created (code: 0x)
    StandardEOA --> DelegatedAccount: Type 0x04 Auth (address: 0xTarget)
    DelegatedAccount --> Revoking: Auth Tuple (address: 0x00...00, nonce: N+1)
    Revoking --> StandardEOA: EVM Clears Bytecode (code: 0x)

Common Failures During Emergency Revocation

When users and automated security systems attempt to revoke compromised delegations, three major failure modes occur:

1. RPC Parameter Rejection: Invalid address

Older Ethereum client implementations or third-party RPC proxies apply schema validation checks that flag address: "0x0000000000000000000000000000000000000000" as invalid or uncallable, throwing:

RPC Error: [-32602] Invalid params: delegate address cannot be zero address

Remedy: Ensure your RPC node runs Geth v1.14.8+ or Nethermind v1.27.0+, and use raw transaction broadcasting rather than abstracted high-level wallet wrappers.

2. Nonce Mismatch Race Condition

If an attacker has already compromised the delegated logic, they may continuously broadcast transactions from the compromised EOA to increment the account nonce. If your revocation tuple specifies nonce $N$, but the attacker pushes a transaction with nonce $N$, your revocation fails with InvalidAuthorizationNonce. Remedy: Submit the revocation as a self-sponsored bundle via Flashbots Protect or a private builder endpoint with an aggressive priority fee (maxPriorityFeePerGas).

Step-by-Step Revocation Guide (Using Viem)

Below is the production script to revoke an EIP-7702 delegation using Viem:

import { createWalletClient, createPublicClient, http, zeroAddress } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { mainnet } from 'viem/chains';

async function revokeEip7702Delegation(privateKey: `0x${string}`, rpcUrl: string) {
  const account = privateKeyToAccount(privateKey);

  const publicClient = createPublicClient({
    chain: mainnet,
    transport: http(rpcUrl),
  });

  const walletClient = createWalletClient({
    account,
    chain: mainnet,
    transport: http(rpcUrl),
  });

  // 1. Fetch current on-chain nonce
  const currentNonce = await publicClient.getTransactionCount({
    address: account.address,
  });

  console.log(`[!] Current EOA Nonce: ${currentNonce}`);
  console.log(`[*] Preparing EIP-7702 Revocation for account: ${account.address}`);

  // 2. Sign Authorization Tuple pointing to Address Zero (0x0000...0000)
  const authorization = await walletClient.signAuthorization({
    contractAddress: zeroAddress, // 0x0000000000000000000000000000000000000000
    chainId: mainnet.id,
    nonce: currentNonce,
  });

  // 3. Broadcast Type 0x04 Transaction with the revocation authorization
  // An empty transaction to self with the authorization list clears the delegation
  const txHash = await walletClient.sendTransaction({
    to: account.address,
    value: 0n,
    authorizationList: [authorization],
    // High gas fees to outbid front-running bots
    maxPriorityFeePerGas: 5_000_000_000n, // 5 gwei
  });

  console.log(`[+] Revocation transaction broadcast: ${txHash}`);

  // 4. Wait for receipt and verify code removal
  const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
  console.log(`[+] Confirmed in block ${receipt.blockNumber}`);

  const onChainCode = await publicClient.getBytecode({ address: account.address });
  if (!onChainCode || onChainCode === '0x') {
    console.log(`[✔] SUCCESS: Account code successfully reset to clean EOA state.`);
  } else {
    console.error(`[X] WARNING: Account still contains bytecode: ${onChainCode}`);
  }
}

On-Chain Verification

After the revocation transaction confirms, verify the state of your account using cast (from the Foundry suite):

# Verify the bytecode of the EOA
cast code 0xYourEOAAddress --rpc-url https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY
  • Prior to Revocation: Returns 0xef0100 followed by the 20-byte delegate address.
  • Post Revocation: Returns 0x (standard empty EOA bytecode).

Once the bytecode returns 0x, the account has fully severed its link to the delegated contract, restoring native cryptographic security to your private key.

Interactive Diagnostic Sandbox

Local UserOp & Protocol Security Sandbox

Decode UserOperation calldata, simulate prefund accounting, and test bundler validation rules in your local browser.

Companion Diagnostic Guide EIP-7702 Delegation Replay Vulnerability →

Prevent cross-chain replay attacks on EIP-7702 account delegation designations. Validate chain ID binding and nonce management in authorization tuples.

Read Guide
Contextual Architecture

Related Diagnostic Guides

View All in Silo →

Related Inquiries

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

Sign and broadcast an EIP-7702 authorization tuple targeting address(0) (0x0000000000000000000000000000000000000000) using the exact current nonce of your EOA. Once included in an execution block, the client runtime clears the delegation pointer.

Can a malicious relayer front-run an EIP-7702 revocation authorization?

Yes, if the relayer observes the revocation in the public mempool and submits a conflicting authorization tuple using the same nonce. Always submit revocation transactions directly via private RPC endpoints or Flashbots Protect.

Does revoking an EIP-7702 delegation reset your account nonce?

No. Processing the revocation authorization tuple increments your account nonce by 1, which invalidates all previously signed pending authorizations that relied on the pre-revocation nonce.

Where can I inspect and decode EIP-7702 authorization payloads?

You can inspect raw EIP-7702 authorization tuples, verify nonces, and simulate Account Abstraction executions client-side using our ERC-4337 UserOp & Calldata Decoder tool.