ByAUJay
Summary: Startups and enterprises are embracing smart accounts and delegated permissions—but every delegation adds operational risk. This deep guide explains concrete key rotation and recovery strategies for ERC‑4337 smart accounts and post‑Pectra EIP‑7702 EOAs, with exact transaction patterns, module choices, monitoring signals, and runbooks you can ship this quarter.
De-risking Delegation: Key Rotation and Recovery Strategies for Smart Accounts
Decision‑makers love what delegation unlocks: one‑click UX, automated ops, spend controls, bots, and device‑native passkeys. But the moment you delegate authority—via a module, plug‑in, session key, paymaster, or (now) EIP‑7702—you assume new failure modes. This post lays out the precise rotation and recovery patterns we deploy at 7Block Labs, mapped to what actually shipped in 2025 (Pectra/EIP‑7702) and today’s production AA stacks (ERC‑4337, ERC‑6900 modules, Safe and Kernel). (blog.ethereum.org)
What changed in 2025: 7702 adds native, temporary delegation for EOAs
- On May 7, 2025 (epoch 364,032), Ethereum activated the Pectra upgrade, which includes EIP‑7702 “Set Code for EOAs.” 7702 introduces a Type‑4 transaction that lets an EOA temporarily point to already‑deployed contract code via an authorization list, then revert back, enabling batching, gas sponsorship, and constrained “sub‑keys” without permanently migrating to a smart contract wallet. (info.etherscan.com)
- Transaction details you need to know (for security policy and tooling):
- Transaction type: 0x04
- New field: authorization_list = [[chain_id, address, nonce, y_parity, r, s], ...]
- Revocation: reset delegation by delegating to the null address
- Cost constants (as specified): PER_AUTH_BASE_COST=12500; PER_EMPTY_ACCOUNT_COST=25000
- Signature domain: secp256k1 over keccak256(0x04 || RLP payload) (eips.ethereum.org)
The big implication: you now manage two delegation surfaces—smart accounts (ERC‑4337) and EOAs (7702). Rotation and recovery must cover both. (eips.ethereum.org)
The delegation threat model (and where teams get burned)
Risk concentrates at the boundaries where “less‑trusted” keys can do “limited” things. In production audits and incidents, we see these categories:
- Session key drift: temporary keys never expire, or their scopes are too broad (target/selector/gas/spend caps missing). (alchemy.com)
- Module misconfiguration: Safe modules/guards with bypass paths, or upgradable plug‑ins without timelocks and quorum. (docs.safe.global)
- Paymaster exposure: token‑gas paymasters drained via poor rate limits, missing whitelists, or weak price oracles. (docs.pimlico.io)
- Bundler fragmentation: private queues or flaky simulation (no ERC‑7562 enforcement) causing DoS or unpredictable inclusion. (eips.ethereum.org)
- 7702 replay/over‑scope: authorizations with chain_id=0 (valid on all chains) or reused nonces, expanding attack blast radius and complicating revocation timing. (ethereum.org)
The rest of this guide gives concrete rotation/recovery patterns that neutralize these failure modes.
Rotation and recovery, by account model
A) ERC‑4337 smart accounts (Safe, Kernel, Modular/6900)
Foundations:
- ERC‑4337 UserOperations live in an alt‑mempool; validation is wallet‑defined, execution via EntryPoint.handleOps. Bundlers enforce simulation rules (see ERC‑7562) and reputation. Your rotation/change events must remain simulatable and respect op‑code/storage constraints. (eips.ethereum.org)
- Modular accounts (ERC‑6900) install validation/execution plug‑ins. Rotating keys typically means updating validator state, not redeploying the account. (erc6900.io)
Concrete rotation patterns we ship:
- Safe owner rotation (no downtime)
- Use Safe’s owner manager functions with deterministic eventing:
- addOwnerWithThreshold, swapOwner, changeThreshold, removeOwner. These are atomic Safe transactions and emit AddedOwner/RemovedOwner/ChangedThreshold for monitoring. (docs.safe.global)
- Runbook:
- Stage: addOwnerWithThreshold(new, same_threshold) → verify EIP‑1271 signatures still resolve.
- Cutover: swapOwner(prev, old, new) to avoid list corruption; Safe stores owners in a linked list—prevOwner must be correct. (docs.safe.global)
- Harden: optionally raise threshold, then remove old owner after a 24h observation window (see alerting below).
- Note: formal verification notes and threshold race considerations exist; prefer “add owner → changeThreshold (increase) → remove old” sequencing to avoid mistaken decreases. (github.com)
- Kernel (ZeroDev) kill‑switch and guardian‑assisted recovery
- Kernel supports validators like KillSwitchValidator to pause and rotate the owner via guardian authority, with a pausedUntil window to contain live attacks. Use this as your “freeze and rotate” circuit breaker. (v3-docs.zerodev.app)
- Social recovery modules
- Install a social recovery module that can only update validator configuration (e.g., add/remove owner, change threshold)—not execute arbitrary transfers. Use 2–3 independent guardians (separate devices/orgs) and require m‑of‑n. Avoid zero timelock on recovery in consumer flows; for enterprise we recommend at least 24h. (docs.rhinestone.dev)
- If using Safe, community implementations and services exist (e.g., Candide’s recovery module). Bake in a grace period and notification channel. (docs.candide.dev)
- Spend/rate control modules to buy time
- Safe’s Allowance/Spending Limit module gives scoped spenders daily/weekly caps; pair this with a Delay/Timelock (Zodiac Delay Modifier) to create a window to cancel surprises. This is a proven pattern in production (e.g., Gnosis Pay uses Delay + Roles). (help.safe.global)
- Guardrails on delegatecalls
- Safe’s Guardrail pattern: allowlist delegatecall targets and time‑delay additions to that allowlist; this blocks “arbitrary multisend via malicious library” class bugs. Use
to wire the guard. (safe.global)setModuleGuard
- Passkey rotation in smart accounts
- If you support WebAuthn passkeys, prefer chains with P‑256 precompile support (RIP‑7212 footprint on major L2s; EIP‑7951 proposes mainnet support with fixes). Coinbase’s smart wallet illustrates passkey owners alongside ECDSA owners and cross‑chain replayable owner updates—design your rotation UX to update new chains lazily on first use. (ethereum-magicians.org)
- Bundler/paymaster hygiene for rotation ops
- Use bundlers that enforce ERC‑7562 and expose error codes (EIP‑7769) to catch broken rotation flows early; Pimlico exposes both. Add a verifying or ERC‑20 paymaster only after you put rate limits/allowlists in place. (eips.ethereum.org)
B) EOAs via EIP‑7702 (post‑Pectra)
7702 brings native, revocable delegation into scope for your rotation policy:
- Authorizations are tuples signed by the EOA key, scoped by chain_id and nonce. Do not use chain_id=0 in enterprise contexts—prefer per‑chain authorization to prevent cross‑chain surprises. Rotate authorizations frequently; never reuse nonces. (ethereum.org)
- Revocation is explicit: send a Type‑4 transaction with authorization that sets the delegation designator to the null address. Keep a pre‑signed revocation ready (stored offline) when rolling out new delegates. (ethereum.org)
Minimal Type‑4 example (Viem‑style):
// Pseudocode: sign and send a 7702 “set code” tx to delegate EOA to a smart account const authorization = await walletClient.signAuthorization({ contractAddress: "0xYourSmartAccountImpl", // code target executor: "self" // executing in EOA context }); await walletClient.sendTransaction({ type: 'eip7702', to: eoaAddress, // destination cannot be null data: "0x", // optional call authorizationList: [authorization], chainId, gas: 250_000 }); // To revoke later: signAuthorization({ contractAddress: zeroAddress }) and send again.
Operational tip: log and reconcile authorizations per chain; treat each as a sensitive change request with reviewer sign‑off. (eip7702.io)
Session keys you won’t regret later
Session keys are where most “delegation sprawl” starts. Scope them like API tokens—not like owners.
What good looks like (Alchemy’s Session Key plugin sets a bar):
- Time bounds: validAfter/validUntil
- Address and selector allowlists/denylists
- Spend caps for both native and ERC‑20 (total and interval refresh)
- Gas cap and optional rate limiting
- Key rotation without changing the policy envelope
If your session‑key framework cannot express those constraints, don’t ship it. Use ERC‑6900/7579‑compatible modules such as SessionKeyPlugin or SmartSession so you can standardize policies across account vendors. (alchemy.com)
Recovery building blocks (that actually get used)
- Social guardians: 3–5 guardians across independent factors (one HSM/enterprise key, one hardware wallet, one partner org, one consumer passkey). Enforce threshold ≥2, with on‑chain delay for finalization in consumer contexts. Educate users on what a guardian can do (change owners) and what it cannot (spend funds). (docs.rhinestone.dev)
- Delay modifier in front of modules: queue, cooldown, execute—lets you “pull the brake” on suspicious flows. Keep an emergency “skip nonce” sequence documented and tested. (github.com)
- Budget/allowance modules for teams: mint sub‑allowances per department with natural‑date resets (month/quarter), escrowed from a master cap; this constrains the blast radius if a downstream delegate is compromised. (docs.firm.org)
- Counterfactual signatures during migration: if you’re rotating to a counterfactual account, use ERC‑6492 so off‑chain verification recognizes the new signer pre‑deployment (e.g., during account migration or “sign‑in with wallet” flows). (eips.ethereum.org)
Concrete rotation runbooks you can adopt
1) Key compromise on a production Safe (ERC‑4337 or multisig)
- Freeze
- If Kernel: trigger KillSwitchValidator pause; if Safe: raise threshold immediately (if feasible) and enable a Guard that blocks unknown delegatecalls. (hackmd.io)
- Contain
- Disable session‑key plug‑ins; revoke spending limits for non‑critical delegates.
- Turn off verifying/erc‑20 paymasters or set paymaster_whitelist = {} to stop gas sponsorship. (github.com)
- Rotate
- addOwnerWithThreshold(newOwner, threshold+1) → swapOwner(prev, old, new) → changeThreshold(back to normal) → removeOwner(prevOfOld, old, threshold). (docs.safe.global)
- Recover
- Re‑issue session keys using a templated policy (time‑boxed, scoped) and re‑enable paymaster with constrained policy.
- Verify
- Watch for AddedOwner/RemovedOwner/ChangedThreshold and EntryPoint UserOperation events; reconcile against your change ticket. (docs.safe.global)
2) Session key suspected leak (gaming bot, subscriptions)
- Disable the module or remove the key in the module’s storage.
- Re‑issue a key with:
- validUntil ≤ 7 days, target allowlist = {app contracts}, selectors = {needed methods}, daily ERC‑20 and gas limits.
- Add an ERC‑20 per‑address allowance in Safe Spending Limits for the session executor as a backstop. (help.safe.global)
3) 7702 delegate gone bad (EOA)
- Fire the delegate by sending a revocation Type‑4 transaction (delegation → null). Keep a pre‑funded hot path to send this even if main infra is down.
- Rotate to a new, audited delegate address, using chain‑specific authorizations only.
- Post‑mortem: enforce a 24h timelock for new delegates via internal policy (since 7702 itself doesn’t add a timelock). (ethereum.org)
Monitoring and alerting (ship these dashboards)
Minimum viable signals:
- Safe events: AddedOwner, RemovedOwner, ChangedThreshold; module enable/disable; guard changes. Alert on any outside a CAB window. (docs.safe.global)
- ERC‑4337:
- simulateValidation failure rates by class (signature, paymaster, initCode)
- handleOps success/failedOp ratios; inclusion latency
- ERC‑7562 throttling/bans by entity (paymaster/factory) (docs.erc4337.io)
- Paymaster drains: token balances vs. sponsorship rate; off‑chain policy denials vs. on‑chain validations. (docs.pimlico.io)
- 7702 authorizations: per‑chain inventory, last‑used time, dangling (never revoked) entries. (ethereum.org)
Implementation snippets
Safe owner rotation (TypeScript, Protocol Kit)
import { Safe } from '@safe-global/protocol-kit' // add new owner, keep threshold const addTx = await safe.createAddOwnerTx({ ownerAddress: NEW, threshold: CURRENT }) await safe.executeTransaction(addTx) // optional: raise threshold temporarily const inc = await safe.createChangeThresholdTx({ threshold: CURRENT + 1 }) await safe.executeTransaction(inc) // swap old→new (atomic index fix) const swap = await safe.createSwapOwnerTx({ prevOwner, oldOwner: OLD, newOwner: NEW }) await safe.executeTransaction(swap) // lower back threshold const dec = await safe.createChangeThresholdTx({ threshold: CURRENT }) await safe.executeTransaction(dec) // finally, remove OLD const rm = await safe.createRemoveOwnerTx({ ownerAddress: OLD, newThreshold: CURRENT }) await safe.executeTransaction(rm)
Events to watch: AddedOwner, RemovedOwner, ChangedThreshold. (docs.safe.global)
Kernel kill‑switch enablement (concept)
// Guardian flips paused and sets new owner for the Kernel account guardian.rotateOwner(newOwner); guardian.pauseUntil(block.timestamp + 1 days);
Design: guardianship separate from owner; validator checks guardian path first when pause flag is set. (hackmd.io)
Session key with tight scope (ERC‑6900 plugin)
await sessionKeyPlugin.addKey({ pubkey: SESSION_PUBKEY, validAfter: now, validUntil: now + 7*24*3600, allow: { addresses: [DEX_ROUTER, USDC, MY_APP], selectors: ['0x095ea7b3' /*approve*/, '0x12aa3caf' /*swap*/], }, caps: { nativeDaily: parseEther('0.01'), erc20Daily: [{ token: USDC, cap: 200_00 }], // $200 gasDaily: 1_000_000 } })
Rotate key weekly; keep policy constants stable so rotation is cheap. (alchemy.com)
EIP‑7702: delegate and revoke (Viem examples)
// delegate EOA → Simple7702Account const auth = await walletClient.signAuthorization({ contractAddress: ACCOUNT_IMPL, executor: 'self' }) await walletClient.sendTransaction({ type: 'eip7702', to: eoa, data: '0x', authorizationList: [auth] }) // ... later: revoke const revoke = await walletClient.signAuthorization({ contractAddress: '0x0000000000000000000000000000000000000000' }) await walletClient.sendTransaction({ type: 'eip7702', to: eoa, authorizationList: [revoke] })
Scope authorizations per‑chain; never set chain_id=0 in enterprise prod. (eip7702.io)
Passkeys and rotation, pragmatically
- L2s widely ship P‑256 verification precompiles (RIP‑7212 lineage), enabling WebAuthn passkeys for smart account owners. For mainnet, EIP‑7951 proposes secure P‑256; track status before assuming L1 availability. Design your rotation to prefer L2 first, then back‑port to L1 when standardized. (eip.info)
- Coinbase Smart Wallet demonstrates mixed owner sets (secp256k1 EOA + secp256r1 passkey) and cross‑chain replayable owner updates—use this pattern to “sign once, update many chains,” but log success per chain because owner updates still require per‑chain on‑chain writes upon first use. (github.com)
Emerging best practices (use this as your internal checklist)
Policy and design
- Distinguish owners vs. delegates. Owners are rotated sparingly with quorum/timelock; delegates (session keys, modules) are rotated often with strict scopes.
- For 7702, treat each authorization like a change request: per‑chain, unique nonce, offline revocation prepared, and a mandatory cool‑off window in your ops process. (ethereum.org)
- Use ERC‑6492 when migrating signers to counterfactual accounts—off‑chain verifiers must accept pre‑deploy signatures. (eips.ethereum.org)
Controls and modules
- Pair Spending Limits with a Delay module on any Safe that funds operations; it’s your safety buffer. (help.safe.global)
- Install a Guard to restrict delegatecalls and add a timelocked allowlist process. (safe.global)
- Prefer ERC‑6900/7579‑compatible session‑key modules to avoid vendor lock‑in and get portable policy semantics. (erc6900.io)
Infrastructure
- Don’t pin to one bundler. Multi‑home across at least two providers that enforce ERC‑7562, and monitor simulateValidation vs. on‑chain variance. (eips.ethereum.org)
- If you sponsor gas, start with per‑address allowlists and strict rate limits on your paymaster; default‑deny everything else. (docs.pimlico.io)
Monitoring and response
- Alert on owner/guardian/guard changes and module (en|dis)ables; treat as security events requiring human review.
- Track ERC‑4337 failure classes and reputation warnings; frequent GREP‑/STO‑ rule hits indicate your plug‑ins violate simulation constraints and will be censored by bundlers. (eips.ethereum.org)
Where we see teams over‑ or under‑rotating (and how to right‑size)
- Over‑rotation of owners: creates quorum fatigue and higher change risk. Solution: keep owners stable; rotate delegates (session keys) aggressively.
- Under‑rotation of session keys: keys silently persist for months. Solution: encode expiry into issuance templates (≤ 7 days) and require renewal.
- 7702 mis‑scoping: chain_id=0 “for convenience.” Solution: per‑chain authorizations only, with an emergency revocation packet lodged in a separate ops account. (ethereum.org)
Action plan you can execute this quarter
- Week 1: Inventory
- List every delegate surface: session keys, modules, guards, paymasters, and any 7702 authorizations; classify by scope and expiry.
- Week 2: Control install
- Add Safe Spending Limits + Delay; add delegatecall Guard; migrate session keys to ERC‑6900/7579 modules with time/address/selector/spend caps. (help.safe.global)
- Week 3: Rotation pipelines
- Build scripts for Safe owner rotation; Kernel kill‑switch playbooks; 7702 delegate+revoke templates; pre‑sign revocation packets.
- Week 4: Monitoring
- Dashboards for Safe owner events, 7702 authorizations per chain, ERC‑4337 simulateValidation failure classes, paymaster balances and rejection rates. (docs.erc4337.io)
If you want a second set of eyes, 7Block Labs can review your module graph, write or audit guards, and implement the runbooks above with your stack (Safe, Kernel, Pimlico, Alchemy, Coinbase Smart Wallet).
References and implementation notes
- EIP‑7702 specification, examples, and ethereum.org guidance (Type‑4, authorization_list, revocation). (eips.ethereum.org)
- Pectra activation details and timelines (EF blog, Etherscan, The Block). (blog.ethereum.org)
- ERC‑4337 core and bundler operations; ERC‑7562 validation rules and reputation. (eips.ethereum.org)
- ERC‑6900 modules; session key plugins; SmartSession (ERC‑7579). (erc6900.io)
- Safe modules and guards; Spending Limits; Guardrail; Zodiac Delay. (help.safe.global)
- Passkeys on L2s (RIP‑7212 lineage) and EIP‑7951; Coinbase Smart Wallet passkey/owner model. (ethereum-magicians.org)
- ERC‑6492 counterfactual signature validation for migrations. (eips.ethereum.org)
7Block Labs builds and audits production‑grade key management and delegation for smart accounts. If you’d like a 2‑week implementation sprint to put these rotations and recoveries in place, we’ll tailor the modules, guards, and runbooks to your chain mix and infrastructure.
Like what you're reading? Let's build together.
Get a free 30‑minute consultation with our engineering team.

