CVE-2025-46834 Overview
CVE-2025-46834 is an authorization bypass vulnerability [CWE-863] in Alchemy's Modular Account, a smart contract account compatible with ERC-4337 and ERC-6900. The flaw affects versions on the 2.x branch prior to commit 5e6f540d249afcaeaf76ab95517d0359fde883b0. The allowlist module fails to validate calls routed through the executeUserOp path that wrap execute or executeBatch selectors. Session keys granted with scoped permissions can bypass allowlist restrictions and interact with any external contract, including ERC20 and ERC721 tokens. Attackers holding a session key can drain funds, reconfigure module permissions, or rotate keys to escalate privileges.
Critical Impact
Any granted session key can bypass allowlist restrictions to transfer all tokens from the account or escalate privileges by rotating higher-privileged keys.
Affected Products
- Alchemy Modular Account 2.x branch prior to commit 5e6f540d249afcaeaf76ab95517d0359fde883b0
- Modular Account AllowlistModule (src/modules/permissions/AllowlistModule.sol)
- ModuleBase helper (src/modules/ModuleBase.sol)
Discovery Timeline
- 2025-05-15 - CVE-2025-46834 published to NVD
- 2026-06-17 - Last updated in NVD database
Technical Details for CVE-2025-46834
Vulnerability Analysis
Alchemy Modular Account owners can delegate scoped external keys, referred to as session keys, to third parties. The allowlist module enforces which external contract addresses and selectors a session key may invoke. The enforcement logic inspects the selector of the incoming call and routes validation for execute and executeBatch accordingly. When a session key wraps its call inside executeUserOp, the allowlist module extracts the outer selector rather than the inner one, then compares against selectors it does not recognize. The scoped restrictions are silently skipped, granting the key unrestricted access to the account.
Root Cause
The defect lives in _getSelectorAndCalldata within ModuleBase.sol. During pre-execution validation the module receives the raw user operation calldata. When the outer selector is IAccountExecute.executeUserOp, the function did not unwrap the inner selector and calldata before the allowlist enforcement ran. As a result, the allowlist module compared the wrapper selector against execute and executeBatch selectors, matched neither, and bypassed the enforcement branch entirely.
Attack Vector
An attacker holding any granted session key crafts a user operation whose top-level selector is executeUserOp. The wrapped inner call targets an ERC20 transfer, ERC721 transferFrom, or a permission-management function on the account itself. Since the allowlist module does not descend into the wrapped call, the enforcement path is skipped and the operation executes. The attacker can drain tokens, remove restrictions on their own key, or rotate other session keys into keys they control.
}
/// @dev help method that returns extracted selector and calldata. If selector is executeUserOp, return the
- /// selector and calldata of the inner call.
- function _getSelectorAndCalldata(bytes calldata data) internal pure returns (bytes4, bytes memory) {
+ /// selector and calldata of the inner call. This is unique for both validation and execution phases.
+ /// During validation phase, the `data` parameter is the uo's calldata.
+ function _validationPhaseGetSelectorAndCalldata(bytes calldata data)
+ internal
+ pure
+ returns (bytes4, bytes memory)
+ {
+ bytes4 selector = bytes4(data[:4]);
+ if (selector == IAccountExecute.executeUserOp.selector) {
+ // Copy the data to memory
+ bytes memory finalCalldata = data;
+
+ // Bytes arr representation: [bytes32(len), bytes4(executeUserOp.selector), bytes4(actualSelector),
+ // bytes(actualCallData)]
+ assembly ("memory-safe") {
+ // Copy actualSelector into a new var
+ selector := shl(224, mload(add(finalCalldata, 8)))
+
+ let len := mload(finalCalldata)
+
+ // Move the finalCalldata pointer by 8
+ finalCalldata := add(finalCalldata, 8)
+
+ // Shorten bytes array by 8 by: store length - 8 into the new pointer location
+ mstore(finalCalldata, sub(len, 8))
Source: Alchemy Modular Account patch commit
Detection Methods for CVE-2025-46834
Indicators of Compromise
- Unexpected ERC20 or ERC721 outbound transfers from Modular Account addresses initiated by session keys rather than the owner.
- User operations whose calldata begins with the executeUserOp selector and wraps execute or executeBatch targeting token contracts.
- Session key rotations, allowlist modifications, or module reconfiguration transactions signed by a session key rather than the account owner.
Detection Strategies
- Enumerate deployed Modular Account instances and query the implementation commit hash to identify accounts running versions prior to 5e6f540d249afcaeaf76ab95517d0359fde883b0.
- Replay historical user operations through the fixed _validationPhaseGetSelectorAndCalldata logic to identify operations that would have been blocked by the allowlist.
- Alert on any UserOperationEvent referencing a session key that touches a contract address not present in that key's allowlist configuration.
Monitoring Recommendations
- Ingest bundler and account entry point events into a centralized log store and correlate session key signers against allowlist configuration snapshots.
- Monitor for calldata patterns where executeUserOp wraps execute or executeBatch on high-value token contracts.
- Track balance changes on Modular Accounts and alert on outflows that exceed established session key spend expectations.
How to Mitigate CVE-2025-46834
Immediate Actions Required
- Upgrade Modular Account implementations to a build that includes commit 5e6f540d249afcaeaf76ab95517d0359fde883b0 or later.
- Revoke session keys granted to untrusted parties on any account still running a vulnerable 2.x version.
- Audit allowlist and permission module configurations for unauthorized changes made through the bypass.
Patch Information
The fix is delivered in commit 5e6f540d249afcaeaf76ab95517d0359fde883b0. The patch splits selector extraction into _validationPhaseGetSelectorAndCalldata and _executionPhaseGetSelectorAndCalldata, ensuring the inner selector and calldata are unwrapped before the AllowlistModule performs its enforcement check. Details are available in the GitHub Security Advisory GHSA-jhp7-7cq9-m4pv.
Workarounds
- Revoke all session keys until the account has been upgraded to a patched implementation.
- Restrict session key issuance to trusted operators and reduce spend limits at the token contract layer where possible.
- Route account transactions exclusively through the owner key on vulnerable deployments until the fix is applied.
# Verify Modular Account implementation matches the patched commit
git clone https://github.com/alchemyplatform/modular-account.git
cd modular-account
git log --oneline | grep 5e6f540d249afcaeaf76ab95517d0359fde883b0
# Rebuild and redeploy the account implementation with the fixed commit
forge build
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

