Skip to main content
Sigvex

AA Signature Audit

Detects signature vulnerabilities in account abstraction implementations including missing chain ID, replay across accounts, and malleability.

AA Signature Audit

Overview

Remediation Guide: How to Fix AA Signature Audit

The AA signature audit detector examines signature verification in ERC-4337 validateUserOp implementations for vulnerabilities specific to account abstraction contexts. These include missing chain ID binding, cross-account replay (where a signature valid for one smart account works on another with the same owner), and improper handling of the userOpHash provided by the EntryPoint.

Why This Is an Issue

Smart accounts validate user operations via signatures. Unlike EOA transactions where the protocol enforces chain ID and nonce, smart accounts must explicitly include these in their signature scheme. Common issues:

  • Re-deriving the hash: Computing a new hash from UserOp fields instead of using the EntryPoint-provided userOpHash (which includes EntryPoint address and chain ID).
  • Cross-account replay: Signature valid for account A also valid for account B if both share an owner and the signature does not bind to the account address.
  • Missing nonce validation: The EntryPoint manages nonces, but custom validation may bypass this.

How to Resolve

// Before: Re-derives hash without chain ID
function validateUserOp(PackedUserOperation calldata op, bytes32 userOpHash, uint256 funds)
    external returns (uint256)
{
    bytes32 hash = keccak256(abi.encode(op.sender, op.nonce, op.callData));
    address signer = ECDSA.recover(hash, op.signature); // Missing chain ID!
    return signer == owner ? 0 : 1;
}

// After: Use EntryPoint-provided hash
function validateUserOp(PackedUserOperation calldata op, bytes32 userOpHash, uint256 funds)
    external returns (uint256)
{
    // userOpHash already includes EntryPoint address, chain ID, and all op fields
    address signer = ECDSA.recover(
        MessageHashUtils.toEthSignedMessageHash(userOpHash),
        op.signature
    );
    return signer == owner ? 0 : 1;
}

Examples

Sample Sigvex Output

{
  "detector_id": "aa-signature-audit",
  "severity": "medium",
  "confidence": 0.74,
  "description": "validateUserOp() computes its own hash at offset 0x3c instead of using the provided userOpHash parameter. The custom hash may lack chain ID binding, enabling cross-chain signature replay.",
  "location": { "function": "validateUserOp()", "offset": 60 }
}

Detection Methodology

  1. Hash usage tracking: Checks whether the userOpHash parameter (second argument) is passed to the signature recovery function.
  2. Custom hash detection: Identifies keccak256 operations within validation that re-derive the hash from UserOp fields.
  3. Chain ID inclusion: Verifies that chain ID is included in any custom hash derivation.
  4. Malleability check: Ensures signature recovery uses a library that rejects malleable signatures (s-value in upper half).

Limitations

  • Cannot determine whether a custom hash scheme is intentionally different (e.g., multi-chain accounts that deliberately omit chain ID).
  • EIP-712 typed data signatures with proper domain separator are recognized but complex nested structures may not be fully parsed.

References