Skip to main content
Sigvex

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

Remediation Guide: How to Fix Account Abstraction (ERC-4337)

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

  1. ERC-4337 interface detection: Identifies contracts implementing IAccount.validateUserOp by selector matching.
  2. Banned opcode scan: Checks the validation function for TIMESTAMP, BLOCKHASH, COINBASE, DIFFICULTY, GASLIMIT, GASPRICE, BALANCE, SELFBALANCE.
  3. Storage access analysis: Verifies SLOAD/SSTORE targets are within associated storage rules (own slots, sender’s deposit in EntryPoint).
  4. 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 PackedUserOperation format may not be recognized in older implementations.

References