Skip to content
Chimera readability score 0.5621 out of 100, reading level.

Six mistakes in ERC-4337 smart accounts
Account abstraction transforms fixed “private key can do anything” models into programmable systems that enable batching, recovery and spending limits, and flexible gas payment. But that programmability introduces risks: a single bug can be as catastrophic as leaking a private key.
After auditing dozens of ERC‑4337 smart accounts, we’ve identified six vulnerability patterns that frequently appear. By the end of this post, you’ll be able to spot these issues and understand how to prevent them.
How ERC-4337 works
Before we jump into the common vulnerabilities that we often encounter when auditing smart accounts, here’s the quick mental model of how ERC-4337 works. There are two kinds of accounts on Ethereum: externally owned accounts (EOAs) and contract accounts.
EOAs are simple key-authorized accounts that can’t run custom logic. For example, common flows like token interactions require two steps (approve/permit, then execute), which fragments transactions and confuses users.
Contract accounts are smart contracts that can enforce rules, but cannot initiate transactions on their own.
Before account abstraction, if you wanted wallet logic like spending limits, multi-sig, or recovery, you’d deploy a smart contract wallet like Safe. The problem was that an EOA still had to kick off every transaction and pay gas in ETH, so in practice, you were juggling two accounts: one to sign and one to hold funds.
ERC-4337 removes that dependency. The smart account itself becomes the primary account. A shared EntryPoint
contract and off-chain bundlers replace the EOA’s role, and paymasters let you sponsor gas or pay in tokens instead of ETH.
Here’s how ERC-4337 works:
Step 1: The user constructs and signs a
UserOperation
off-chain. This includes the intended action (callData
), a nonce, gas parameters, an optional paymaster address, and the user’s signature over the entire message.Step 2: The signed
UserOperation
is sent to a bundler (think of it as a specialized relayer). The bundler simulates it locally to check it won’t fail, then batches it with other operations and submits the bundle on-chain to theEntryPoint
viahandleOps
.Step 3: The
EntryPoint
contract callsvalidateUserOp
on the smart account, which verifies the signature is valid and that the account can cover the gas cost. If a paymaster is involved, theEntryPoint
also validates that the paymaster agrees to sponsor the fees.Step 4: Once validation passes, the
EntryPoint
calls back into the smart account to execute the actual operation. The following figure shows theEntryPoint
flow diagram from ERC-4337:
If you’re not already familiar with ERC-4337 or want to dig into the details we’re glossing over here, it’s worth reading through the full EIP. The rest of this post assumes you’re comfortable with the basics.
Now that we’ve covered the ERC-4337 attack surface, let’s explore the common vulnerability patterns we encounter in our audits.
1. Incorrect access control
If anyone can call your account’s execute
function (or anything that moves funds) directly, they can do anything with your wallet. Only the EntryPoint
contract should be allowed to trigger privileged paths, or a vetted executor module in ERC-7579.
A vulnerable implementation allows anyone to drain the wallet:
While in a safe implementation, the execute
function is callable only by entryPoint
:
Here are some important considerations for access control:
For each
external
orpublic
function, ensure that the proper access controls are set.In addition to the
EntryPoint
access control, some functions need to restrict access to the account itself. This is because you may frequently want to call functions on your contract to perform administrative tasks like module installation/uninstallation, validator modifications, and upgrades.
2. Incomplete signature validation (specifically the gas fields)
A common and serious vulnerability arises when a smart account verifies only the intended action (for example, the callData
) but omits the gas-related fields:
preVerificationGas
verificationGasLimit
callGasLimit
maxFeePerGas
maxPriorityFeePerGas
All of these values are part of the payload and must be signed and checked by the validator. Since the EntryPoint
contract computes and settles fees using these parameters, any field that is not cryptographically bound to the signature and not sanity-checked can be altered by a bundler or a frontrunner in transit.
By inflating these values (for example, preVerificationGas
, which directly reimburses calldata/overhead), an attacker can cause the account to overpay and drain ETH. preVerificationGas
is the portion meant to compensate the bundler for work outside validateUserOp
, primarily calldata size costs and fixed inclusion overhead.
We use preVerificationGas
as the example because it’s the easiest lever to extract ETH: if it isn’t signed or strictly validated/capped, someone can simply bump that single number and get paid more, directly draining the account.
Robust implementations must bind the full UserOperation
, including all gas fields, into the signature, and so enforce conservative caps and consistency checks during validation.
Here’s an example of an unsafe validateUserOp
function:
And here’s an example of a safe validateUserOp
function:
Here are some additional considerations:
Ideally, use the
userOpHash
sent by theEntrypoint
contract, which includes the gas fields by spec.If you must allow flexibility, enforce strict caps and reasonability checks on each gas field.
3. State modification during validation
Writing state in validateUserOp
and then using it during execution is dangerous since the EntryPoint
contract validates all ops in a bundle before executing any of them. For example, if you cache the recovered signer in storage during validation and later use that value in execute
, another op’s validation can overwrite it before yours runs.
In Figure 6, one of the two owners can validate a function, but use the other owner’s address in the execute
function. Depending on how the execute function is supposed to work in that case, it can be an attack vector.
Here are some important considerations for state modification:
Avoid modifying the state of the account during the validation phase.
Remember batch semantics: all validations run before any execution, so any “approval” written in validation can be overwritten by a later op’s validation.
Use a mapping keyed by
userOpHash
to persist temporary data, and delete it deterministically after use, but prefer not persisting anything at all.
4. ERC‑1271 replay signature attack
ERC‑1271 is a standard interface for contracts to validate signatures so that other contracts can ask a smart account, via isValidSignature(bytes32 hash, bytes signature)
, whether a particular hash has been approved.
A recurring pitfall, highlighted by security researcher curiousapple (read the post-mortem here), is to verify that the owner signed a hash without binding the signature to the specific smart account and the chain. If the same owner controls multiple smart accounts, or if the same account exists across chains, a signature created for account A can be replayed against account B or on a different chain.
The remedy is to use EIP‑712 typed data so the signature is domain‑separated by both the smart account address (as verifyingContract
) and the chainId
.
At a minimum, the signed payload must include the account and chain so that a signature cannot be transplanted across accounts or networks. A robust pattern is to wrap whatever needs authorizing inside an EIP‑712 struct and recover against the domain; this automatically binds the signature to the correct account and chain.
Here are some considerations for ERC-1271 signature validations:
Always verify EIP‑712 typed data so the domain binds signatures to
chainId
and the smart account address.Enforce exact ERC‑1271 magic value return (
0x1626ba7e
) on success; anything else is failure.Test negative cases explicitly: same signature on a different account, same signature on a different chain, and same signature after nonce/owner changes.
5. Reverts don’t save you in ERC‑4337
In ERC-4337, once validateUserOp
succeeds, the bundler gets paid regardless of whether execution later reverts. This is the same model as normal Ethereum transactions, where miners collect fees even on failed txs, so planning to “revert later” is not a safety net. The success of validateUserOp
commits you to paying for gas.
This has a subtle consequence: if your validation is too permissive and accepts operations that will inevitably fail during execution, a malicious bundler can submit those operations repeatedly, each time collecting gas fees from your account without anything useful happening.
A related issue we’ve seen in audits involves paymasters that pay the EntryPoint
from a shared pool during validateUserOp
, then try to charge the individual user back in postOp
. The problem is that postOp
can revert (bad state, arithmetic errors, risky external calls), and a revert in postOp
does not undo the payment that already happened during validation. An attacker can exploit this by repeatedly passing validation while forcing postOp
failures by withdrawing his ETH from the pool during the execution of the userOp
, for example, and draining the shared pool.
The robust approach is to never rely on postOp
for core invariants. Debit fees from a per-user escrow or deposit during validation, so the money is secured before execution even begins. Treat postOp
as best-effort bookkeeping: keep it minimal, bounded, and designed to never revert.
Here are some important considerations for ERC-4337:
Make
postOp
minimal and non-reverting: avoid external calls and complex logic, and instead treat it as best-effort bookkeeping.Test both success and revert paths. Consider that once the
validateUserOp
function returns a success, the account will pay for the gas.
6. Old ERC‑4337 accounts vs ERC‑7702
ERC‑7702 allows an EOA to temporarily act as a smart account by activating code for the duration of a single transaction, which effectively runs your wallet implementation in the EOA’s context. This is powerful, but it opens an initialization race. If your logic expects an initialize(owner)
call, an attacker who spots the 7702 delegation can frontrun with their own initialization transaction and set themselves as the owner. The straightforward mitigation is to permit initialization only when the account is executing as itself in that 7702‑powered call. In practice, require msg.sender == address(this)
during initialization.
This works because, during the 7702 transaction, calls executed by the EOA‑as‑contract have msg.sender == address(this)
, while a random external transaction cannot satisfy that condition.
Here are some important considerations for ERC-7702:
Require
msg.sender == address(this)
andowner == address(0)
in initialize; make it single‑use and impossible for external callers.Create separate smart accounts for ERC‑7702–enabled EOAs and non‑7702 accounts to isolate initialization and management flows.
Quick security checks before you ship
Use this condensed list as a pre-merge gate for every smart account change. These checks block some common AA failures we see in audits and production incidents. Run them across all account variants, paymaster paths, and gas configurations before you ship.
Use the
EntryPoint
’suserOpHash
for validation.Restrict
execute
/privileged functions toEntryPoint
(and self where needed).Keep
validateUserOp
stateless: don’t write to storage.Force EIP‑712 for ERC‑1271 and other signed messages.
Make
postOp
minimal, bounded, and non‑reverting.For ERC‑7702, allow init only when
msg.sender == address(this)
, once.Add multiple end-to-end tests on success and revert paths.
If you need help securely implementing smart accounts, contact us for an audit.

Facts Only

ERC-4337 enables programmable smart accounts, replacing traditional EOAs on Ethereum.
Smart accounts allow features like batching, recovery, and flexible gas payments.
Six common vulnerability patterns are identified in ERC-4337 smart accounts.
Incorrect access control can allow unauthorized execution of privileged functions.
Incomplete signature validation, particularly of gas fields, can lead to ETH drainage.
State modification during validation can cause inconsistent execution due to batch processing.
ERC-1271 replay signature attacks can occur if signatures are not domain-separated by account and chain.
Reverting during execution does not prevent gas fees from being paid, creating opportunities for abuse.
ERC-7702 introduces initialization races where attackers can frontrun account setup.
The EntryPoint contract validates and executes UserOperations in batches.
Bundlers simulate and submit UserOperations to the EntryPoint contract.
Paymasters can sponsor gas fees or allow token-based payments.
The article provides examples of unsafe and safe implementations for each vulnerability.
A checklist is included for developers to verify security before deployment.

Executive Summary

ERC-4337 introduces account abstraction, allowing programmable smart accounts to replace traditional externally owned accounts (EOAs) on Ethereum. This enables features like batching transactions, recovery mechanisms, and flexible gas payments. However, the programmability introduces new security risks. The article identifies six common vulnerability patterns in ERC-4337 smart accounts: incorrect access control, incomplete signature validation, state modification during validation, ERC-1271 replay signature attacks, reliance on reverts for safety, and initialization races in ERC-7702 accounts. Each vulnerability is explained with examples of unsafe and safe implementations, emphasizing the need for strict access controls, comprehensive signature validation, stateless validation, and careful handling of post-operation logic. The analysis also provides a checklist for developers to avoid these pitfalls before deployment.
The article assumes familiarity with ERC-4337 basics, focusing on practical security considerations. It highlights how bundlers and attackers can exploit poorly implemented smart accounts, such as draining ETH by manipulating gas fields or replaying signatures across accounts. The recommendations include using EIP-712 for domain-separated signatures, restricting privileged functions to the EntryPoint contract, and ensuring post-operation logic is minimal and non-reverting. The piece serves as both a warning and a guide for developers working with account abstraction, underscoring the importance of rigorous testing and auditing.

Full Take

This analysis of ERC-4337 vulnerabilities serves as a critical reminder of the trade-offs between innovation and security in blockchain systems. The strongest version of this narrative is its pragmatic focus on actionable security patterns, grounded in real-world audit findings. It avoids sensationalism, instead offering clear technical guidance for developers. The piece effectively steelmans the case for rigorous security practices in smart account implementation, acknowledging both the power and risks of account abstraction.
Pattern-wise, the article avoids manipulation tactics, presenting a straightforward technical assessment. No emotional exploitation, distortion, or bad faith arguments are detected. The root cause of these vulnerabilities lies in the inherent complexity of programmable accounts, where flexibility introduces attack surfaces not present in simpler EOAs. The paradigm shift from static key-based accounts to dynamic smart contracts demands a corresponding evolution in security practices.
The implications for human agency are significant: while ERC-4337 empowers users with more control over their accounts, poor implementations can lead to catastrophic losses. Developers bear the responsibility of ensuring these systems are secure, but end-users may lack the expertise to evaluate risks. Second-order consequences include potential erosion of trust in account abstraction if exploits become widespread, or conversely, broader adoption if security standards improve.
Bridge questions: How might the security risks of ERC-4337 compare to those of traditional smart contract wallets like Safe? What incentives could encourage bundlers to reject malicious operations proactively? How can end-users verify the security of their smart accounts without technical expertise?
Counterstrike scan: A coordinated influence campaign might exaggerate the risks of ERC-4337 to discourage adoption or downplay them to promote reckless implementation. This article does neither—it provides balanced, technical guidance without overstating threats or underplaying risks. The content aligns with genuine security education rather than manipulation.
Patterns detected: none

Sentinel — Human

Confidence

This article exhibits strong human authorship signals, with technical depth, stylistic idiosyncrasies, and verifiable attributions inconsistent with synthetic generation.

Signals Detected
low severity: Moderate sentence length variance with some uniform patterns, but includes idiosyncratic phrasing and technical depth inconsistent with typical AI output.
low severity: Strong technical voice with passionate emphasis on security implications, not the balanced-but-flat tone typical of AI.
low severity: No template-matching or verbatim talking points; arguments are structurally organic and contextually grounded.
low severity: All claims are attributed to verifiable standards (ERC-4337, EIP-712) or specific researcher post-mortems (curiousapple).
Human Indicators
Deep domain expertise evident in nuanced explanations of gas field validation and ERC-1271 replay attacks.
Idiosyncratic phrasing like 'juggling two accounts' and 'metronomic middle' (in the instructions, not article) suggests human stylistic fingerprint.
Technical diagrams and code snippets are integrated naturally, not as generic placeholders.