
Loading...
Loading
Loading...
LoadingLoading audit report...

WalletGuard.ai, powered by Gestalt Labs
Forge fork-validation ran but no findings met the threshold for PoC inclusion. See the per-finding "Forge validated" badges in the report below for individual results.
The analyzed contract is a modular smart account system implementing ERC-4337, session-based authorization, recovery mechanisms, and a flexible signature validation framework. The analysis identified 0 critical, 1 high, 10 medium, 9 low, and 4 informational findings across 31 total submissions after deduplication and scope gating. The single most dangerous pattern is the Estimator contract's complete bypass of both nonce validation and image hash verification, allowing any caller to execute arbitrary calls through the Estimator with no real authorization. While several of these issues affect auxiliary or helper contracts intended for off-chain simulation, their deployment as live on-chain contracts without adequate access controls introduces meaningful risk; the overall security posture requires targeted remediation before the contract can be considered production-safe.
The Estimator contract, which is deployed on-chain as a live contract, skips both the nonce check and the signature authorization check. This means any person can submit any payload to it and have arbitrary calls executed as if they were authorized. There is no real authentication gate, so the Estimator is essentially an open execution environment.
The Simulator contract allows anyone to trigger delegatecalls to any address in the context of the Simulator contract itself. Because the Simulator inherits real wallet storage (including the implementation pointer, nonces, and image hash), an attacker can overwrite these values or drain any ETH held by the contract, effectively taking full control of the Simulator.
The Recovery contract's signature validation does not check whether the cryptographic recovery operation returned the zero address. If a recovery configuration is ever set up with the zero address as a signer, an attacker can provide a junk signature and successfully authenticate. Even without that specific misconfiguration, the missing check represents a defense-in-depth failure for a high-value operation.
3 centralization points identified
The Guest contract is intentionally unauthenticated by design; the risk is a property the buyer should know about, specifically that any funds held by Guest can be drained by anyone.
fallback()Non-standard storage slot for the implementation pointer reduces tooling compatibility and auditability; this is a property buyers should know about rather than a direct exploit path.
_setImplementation()This is an intentional but unconventional design choice with no direct exploit path in isolation; it is a property buyers and integrators should know about.
_setImplementation()Finding 'Estimator._isValidImage always returns true, bypassing image hash validation' disables all signer authorization checks, while 'Estimator uses current nonce instead of payload nonce, enabling replay of any valid signature' disables nonce replay protection. Together, any caller can submit a fabricated payload to Estimator.estimate() that passes both the nonce check (because the contract reads its own current nonce) and the image hash check (which always returns true), resulting in execution of arbitrary calls with no authorization whatsoever. These two bypasses are individually described as design choices for gas estimation but their combination in a live deployed contract creates a fully open execution path.
Finding 'ecrecover return value not checked for address(0) in Recovery.isValidSignature' and its near-duplicate 'Recovery.isValidSignature: ecrecover on invalid/zero signature does not revert, may accept zero-address signer' share the same root cause. If combined with a wallet configuration that includes address(0) as a recovery leaf (a misconfiguration that the contract does not prevent), an attacker can queue an arbitrary payload for that signer using a degenerate signature, then wait out the timelock and execute an unauthorized recovery. The contract has no check that address(0) is excluded from valid recovery signers.
Finding 'PermissionValidator Cumulative Usage Logic Has Silent Race' shows that a zero in-payload usage value is indistinguishable from a cache miss, causing the validator to read from stale storage and potentially double-count. Combined with 'ExplicitSessionManager.incrementUsageLimit allows decrement check bypass via equality', a session operator can call incrementUsageLimit directly to reset the on-chain stored usage to the current value, then trigger the zero-sentinel bug in PermissionValidator to appear as though no usage has occurred in the current payload, effectively resetting per-permission cumulative limits within a multi-call payload.
| Agent | Status | Findings | Severity | Confidence | Duration | Coverage |
|---|---|---|---|---|---|---|
| reentrancy | success | 5 | 2M1L | 61% | 1.1m | Classic reentrancy patterns in execute(), selfExecute(), executeUserOp(), Cross-function reentrancy via shared reentrancy guard storage, ERC-777 tokensReceived hook in Hooks.sol (found: no-op implementation, safe), ERC-1155 onERC1155Received and onERC1155BatchReceived callbacks (found: pure returns, safe), ERC-4626 vault deposit/withdraw patterns (not applicable), ReentrancyGuard implementation correctness (storage-based, correct), Estimator nonce consumption logic, Session manager usage limit validation and increment logic, Recovery contract signature validation, Cross-contract state sharing in session manager, BaseSig.recover external calls to ERC1271 and ISapient contracts, Hooks fallback delegatecall path, Factory.deploy create2 pattern, Guest fallback dispatch pattern, Simulator simulate() function |
| access control | success | 5 | 2M1L | 56% | 58.0s | Access control on all external/public state-modifying functions, ecrecover usage and address(0) check across all files, Signature replay protection (nonce, chainId, domain separator), Signature malleability in BaseSig ECDSA recovery, delegatecall targets in Hooks.sol fallback and Calls.sol execute, Delegatecall in Estimator and Simulator with user-controlled call.to, Initializer protection (no upgradeable proxy pattern found), tx.origin usage (none found), EIP-712 domain separator construction, Recovery contract queue payload authentication, SessionSig attestation signature verification, ExplicitSessionManager incrementUsageLimit access control, Factory deploy function (no access control, intentional), ReentrancyGuard implementation, Static signature expiry check in BaseAuth, Hooks addHook/removeHook onlySelf protection, ERC4337 entrypoint validation, Cross-chain replay in session signatures (chainId included in hashCallWithReplayProtection) |
| economic | success | 7 | 4M2L | 74% | 1.5m | Flash loan attack vectors - no token balance pricing found, Oracle manipulation - no price feed usage found, Governance attacks - voting/governance contracts not present, Sandwich/MEV exposure - no swap operations found, Reentrancy - ReentrancyGuard usage reviewed across Calls, Estimator, ERC4337v07, Nonce handling in Estimator vs Calls, Simulator delegatecall access control, Recovery queue timestamp and signature validation, Session manager explicit/implicit permission validation, SessionSig memory allocation heuristic, ExplicitSessionManager usage limit increment access, BaseSig signature recovery and merkle tree logic, Stage1Auth factory-based image hash verification, Stage2Auth storage-based image hash verification, Hooks fallback delegatecall security, Estimator _isValidImage override, ERC4337v07 entry point validation, ecrecover return value handling, Integer overflow/underflow with Solidity 0.8.x protection, WebAuthn/P256 signature verification, Wallet proxy creation code, LibBytes out-of-bounds reading behavior |
| logic validation | success | 8 | 1H1M3L | 69% | 1.6m | Estimator gas estimation and nonce validation logic, Recovery module signature validation and queue management, SessionManager explicit/implicit session validation, SessionSig signature decoding and replay protection, BaseSig merkle tree recovery (ecrecover, ERC1271, Sapient), BaseAuth static signature and image hash validation, Nonce management and consumption, PermissionValidator cumulative usage tracking, ERC4337v07 entrypoint validation, Hooks delegatecall fallback, Factory wallet deployment (CREATE2), ReentrancyGuard implementation, LibBytes out-of-bounds read behavior, EIP-712 domain separator construction (chainId handling), Passkeys WebAuthn signature verification, Integer arithmetic and overflow in unchecked blocks, State machine transitions (Stage1 to Stage2), Access control (onlySelf, entrypoint checks) |
| code quality | success | 10 | 1L | 77% | 1.7m | Reentrancy in execute/selfExecute/estimate (nonReentrant modifier coverage), Nonce consumption correctness in Estimator vs Calls, Signature validation paths (BaseSig, Recovery, Passkeys), ecrecover return value validation (address(0) checks), Access control on privileged functions (onlySelf, onlyEntryPoint), Session manager permission validation and cumulative usage tracking, Recovery queue payload hash consistency, ERC-1967 proxy slot compliance, LibBytes out-of-bounds read risks, Simulator unauthenticated call execution, ExplicitSessionManager.incrementUsageLimit logic, Factory.deploy CREATE2 deployment, Guest fallback delegate call restriction, Hooks fallback delegatecall to hook targets, ERC4337 validateUserOp entrypoint check, Static signature expiry and caller checks, Chained signature checkpoint ordering, Blacklist binary search correctness, SessionSig attestation index bounds check, WebAuthn verification (P256, challenge, type checks) |
| compiler bugs | success | 4 | 1M1L | 71% | 1.3m | Reentrancy patterns across Calls, Estimator, Simulator, Nonce consumption and replay protection in Estimator vs Calls.execute, Signature validation paths in BaseAuth, BaseSig, Recovery, Passkeys, ecrecover zero-address bypass in Recovery.isValidSignature, SessionManager explicit/implicit session validation logic, PermissionValidator cumulative usage tracking sentinel value logic, ExplicitSessionManager incrementUsageLimit access control, Blacklist binary search correctness in ImplicitSessionManager, Factory CREATE2 deployment and salt collision, Hooks fallback delegatecall target validation, Static signature expiry and caller checks in BaseAuth, Chained signature ordering checks in BaseSig.recoverChained, Compiler bug patterns for pragma ^0.8.x (not in affected ranges for known bugs), ERC4337 validateUserOp entrypoint access control, Storage key collision analysis across modules, Implementation proxy storage slot (address() as key) |
| assembly safety | success | 6 | 1M | 76% | 1.2m | Full codepoint scan for non-ASCII characters, RTLO (U+202E), zero-width joiners (U+200B/U+200C/U+200D), and Cyrillic homoglyphs in all identifiers, comments, and strings — none found, All assembly{} blocks: Storage.sol (sload/sstore with keccak-derived or hardcoded known keys), Implementation.sol (sstore at address()), LibOptim.sol (call/delegatecall patterns), PermissionValidator.sol (mstore array length truncation), SessionSig.sol (mstore array length truncation), SessionManager.sol (mstore array length truncation), Hooks.sol (delegatecall fallback with return), Base64.sol (scratch memory use), P256.sol (staticcall patterns), WebAuthn.sol (sha256 precompile calls), Incorrect Yul shift direction (shl/shr argument order) — none found; all shifts in LibBytes use correct Yul order, Assembly delegatecall success check — Hooks.sol fallback uses delegatecall but checks success via iszero(success) before revert/return; LibOptim.delegatecall returns success bool which callers check, Assembly return() used to exit EVM execution — Hooks.sol fallback uses assembly return() to return delegatecall result, which is the intended behavior, Reentrancy analysis across execute/selfExecute/estimate/executeUserOp paths, Session signature recovery logic including nonce replay, permission bounds, blacklist enforcement, attestation validation, Recovery contract queue/consume payload hash consistency, ERC4337 validateUserOp entrypoint access control, Nonce consumption in Estimator vs Calls, incrementUsageLimit access control and monotonicity, Static signature expiry and caller check in BaseAuth, Stage1Auth counterfactual address validation, Factory create2 deployment |
| l2 specific | success | 9 | 2M2L | 69% | 1.7m | Estimator gas estimation flow and _isValidImage override, Simulator unauthenticated call execution, Guest contract unauthenticated execution, BaseAuth static signature expiry logic, Recovery module hash computation and queue mechanism, Recovery ECDSA signature validation with ecrecover, SessionManager explicit and implicit call validation, ExplicitSessionManager.incrementUsageLimit() access control, BaseSig signature recovery (all flag types: HASH, ADDRESS, ERC1271, BRANCH, NESTED, SUBDIGEST, ETH_SIGN, ANY_ADDRESS, SAPIENT, SAPIENT_COMPACT), Nonce management and replay protection, ReentrancyGuard implementation using custom storage slots, Implementation contract (sstore at address() slot), Factory CREATE2 deployment, Hooks delegate call fallback, ERC4337v07 validateUserOp and executeUserOp, LibBytes out-of-bounds behavior, LibOptim.call and delegatecall wrappers, SessionSig.recoverSignature and recoverConfiguration, Passkeys WebAuthn verification, P256 signature verification, Cross-chain replay protection via noChainId flag |
| upgrade | success | 6 | 1M | 68% | 1.2m | Proxy pattern identification - custom storage-based proxy in Wallet.sol using sstore(address(), _imp), Implementation slot manipulation in Implementation._setImplementation, Storage collision risks between Implementation's address()-based slot and standard contract variables, Initialization risks - Stage1Module and Stage2Module constructors, no initializer pattern, Reentrancy protection via ReentrancyGuard using custom storage slots, Access control on privileged functions (onlySelf, entrypoint checks), Delegatecall to user-supplied addresses in Calls._execute and Simulator.simulate, Session manager authentication and usage limit enforcement, Recovery module signature validation and hash consistency, Nonce handling in Estimator vs production execute path, ERC4337 entrypoint validation in ERC4337v07, Hooks fallback delegatecall to registered hook addresses, BaseSig signature recovery including ERC1271, Sapient, ETH sign variants, SessionSig configuration recovery and blacklist enforcement, Factory deploy with CREATE2, WebAuthn/Passkeys signature verification, P256 signature verification and malleability check, Integer overflow/underflow in usage limit arithmetic, Guest contract call dispatch without authentication |
This automated audit has inherent limitations. The following areas are not covered.
This report is an automated point-in-time assessment and does not guarantee protection against all possible attacks. It does not cover off-chain components, economic modeling, or business logic correctness unless explicitly noted. Changes to the contract after the audit commit are not reviewed. This is not financial or legal advice. WalletGuard, powered by Gestalt Labs, provides this analysis as-is with no warranty of completeness.
[](https://walletguard.ai/audit/27f4eff4-9dbe-48d3-97c8-9625c5b63a73)
<a href="https://walletguard.ai/audit/27f4eff4-9dbe-48d3-97c8-9625c5b63a73"> <img src="https://walletguard.ai/api/badge/27f4eff4-9dbe-48d3-97c8-9625c5b63a73" alt="WalletGuard Audit Badge" /> </a>