Account Abstraction (ERC-4337)
Detects security issues in ERC-4337 account abstraction implementations including validation phase violations, paymaster abuse, and bundler manipulation.
Account Abstraction (ERC-4337)
Overview
The account abstraction detector identifies security vulnerabilities in ERC-4337 smart account implementations, paymasters, and aggregators. It checks for validation phase violations (banned opcodes, storage access restrictions), improper signature verification in validateUserOp, and paymaster abuse vectors.
Why This Is an Issue
ERC-4337 introduces a mempool for user operations that is separate from the standard transaction mempool. The validation phase (validateUserOp) runs off-chain by bundlers before inclusion. If this phase uses banned opcodes (TIMESTAMP, BLOCKHASH, GASPRICE) or accesses unrestricted storage, bundlers cannot safely simulate the operation, enabling griefing attacks against the mempool.
Incorrect signature verification in smart accounts can lead to:
- Unauthorized operation execution
- Replay attacks across chains or accounts
- Signature malleability allowing operation modification
How to Resolve
// Before: Validation uses block.timestamp (banned in validation phase)
function validateUserOp(
PackedUserOperation calldata userOp,
bytes32 userOpHash,
uint256 missingAccountFunds
) external returns (uint256 validationData) {
require(block.timestamp < deadline, "Expired"); // BANNED opcode
_validateSignature(userOp, userOpHash);
return 0;
}
// After: Use validAfter/validUntil in return value
function validateUserOp(
PackedUserOperation calldata userOp,
bytes32 userOpHash,
uint256 missingAccountFunds
) external returns (uint256 validationData) {
bool sigValid = _validateSignature(userOp, userOpHash);
// Pack deadline into validationData (ERC-4337 convention)
return _packValidationData(!sigValid, deadline, 0);
}
Examples
Vulnerable Code
contract VulnerableAccount {
function validateUserOp(
PackedUserOperation calldata userOp,
bytes32 userOpHash,
uint256 missingAccountFunds
) external returns (uint256) {
// Reads external contract storage -- violates ERC-4337 storage rules
require(registry.isAllowed(userOp.sender), "Not allowed");
// Signature check vulnerable to malleability
bytes32 hash = keccak256(abi.encode(userOp));
address signer = ecrecover(hash, v, r, s);
require(signer == owner, "Bad sig");
return 0; // No time validity bounds
}
}
Fixed Code
contract SafeAccount {
function validateUserOp(
PackedUserOperation calldata userOp,
bytes32 userOpHash,
uint256 missingAccountFunds
) external returns (uint256) {
// Only access associated storage (own slots, EntryPoint deposit)
require(msg.sender == ENTRY_POINT, "Not EntryPoint");
// Use EIP-712 typed hash for replay protection
bytes memory sig = userOp.signature;
address signer = ECDSA.recover(userOpHash, sig); // Uses OZ ECDSA
bool valid = signer == owner;
if (missingAccountFunds > 0) {
payable(msg.sender).call{value: missingAccountFunds}("");
}
return _packValidationData(!valid, validUntil, validAfter);
}
}
Sample Sigvex Output
{
"detector_id": "account-abstraction",
"severity": "high",
"confidence": 0.78,
"description": "validateUserOp() accesses external contract storage at offset 0x48 (SLOAD from non-associated address). This violates ERC-4337 validation phase storage rules and will be rejected by bundlers.",
"location": { "function": "validateUserOp()", "offset": 72 }
}
Detection Methodology
- ERC-4337 interface detection: Identifies contracts implementing
IAccount.validateUserOpby selector matching. - Banned opcode scan: Checks the validation function for TIMESTAMP, BLOCKHASH, COINBASE, DIFFICULTY, GASLIMIT, GASPRICE, BALANCE, SELFBALANCE.
- Storage access analysis: Verifies SLOAD/SSTORE targets are within associated storage rules (own slots, sender’s deposit in EntryPoint).
- Signature verification audit: Checks for proper use of
userOpHash(not re-derived), absence of malleability, and chain-specific replay protection.
Limitations
- Cannot fully validate storage association rules when storage slot computation involves complex hashing.
- Paymaster validation (
validatePaymasterUserOp) analysis is limited to opcode and storage checks. - ERC-4337 v0.7 changes to
PackedUserOperationformat may not be recognized in older implementations.
Related Detectors
- AA Storage Access — banned opcodes in ERC-4337 validation phase
- AA Signature Audit — signature vulnerabilities in AA implementations
- Signature Verification — general signature verification issues
- EIP-7702 Delegation — delegation target vulnerabilities