The Fireblocks research team recently uncovered an ERC-4337 Account Abstraction vulnerability in the smart contract wallet UniPass. Fireblocks worked with UniPass to fully mitigate the vulnerability, which was found in hundreds of mainnet wallets in a whitehat operation. All funds are now safe and accounted for.
Vulnerability Risk Profile
The vulnerability allows an attacker to perform a full account takeover of UniPass wallets that activates the account abstraction module by replacing the trusted EntryPoint of the wallet. Once the account takeover is complete, an attacker would be able to access the wallet as his own and drain all funds from it.
Several hundred users that had the ERC-4337 module in the wallet activated were vulnerable to this attack, which could be performed by anyone on the blockchain. These wallets held small amounts of money, so this issue has been mitigated very early – and we are providing a technical analysis of the vulnerability as it will be useful for protecting the entire ERC-4337 ecosystem.
After the vulnerability was identified and validated to be real and exploitable, our research team found a way to resolve it. Fixing the module installation process would only solve it for future users, so we came up with a whitehat operation that would patch the existing vulnerable wallets by being the first to exploit the vulnerability. We shared this idea with the UniPass team, who took it upon themselves to implement and run the whitehat operation. We appreciate UniPass’ rapid collaboration, which ensured a quick resolution to this issue.
Technical Deep Dive
Read on for a full technical explanation of the vulnerability we discovered, and the solution we created for its mitigation.
ERC-4337 Trust Assumptions
Before we dive into the vulnerable code, here is an overview of how ERC-4337 works, and the trust assumptions that entails:
When an ERC-4337-compliant account executes an action, they rely on the Entrypoint contract to make sure only “validated user operations” (AKA signed transactions) get executed.
They usually trust a single EntryPoint contract after having audited it to ensure it always calls “validateUserOp,” and that it receives the OK from the account before going on to execute the operation.
It’s important to note that a malicious or buggy entrypoint could, in theory, skip the call to “validateUserOp” and just call the execution function directly, as the only restriction it has is that it’s called from the trusted EntryPoint.
Key takeaway: The ERC-4337-compliant account is completely trusting the EntryPoint contract, and a malicious trusted EntryPoint contract would have complete control over the smart accounts that trust it.
The vulnerability
The vulnerability consists of 3 distinct issues that are not exploitable individually, but when combined, can be exploited to gain owner-level access to a wallet.
1. The first issue is that the validateSignature function returns “success=true” for an empty signature:
This by itself is not exploitable because it also returns zero weights, and the UniPass wallets use a weighted role-based access control system:
Although the validateSignature function returns “success=true” for an empty signature, it also returns 0 for all the role weights, which supposably does no harm (no role weights = no permissions).
2. The second issue has to do with calculating how many role weights are needed to call privileged functions on the contract itself.
If the function called is not one of the built-in functions (such as in the case of module functions), getRoleOfPermission will look up the 4-byte signature (`_permission`) of the function being called in the `permissions` storage mapping, and return the assigned required weights.
These weights are assigned via the `addPermission` function.
So, what’s the problem here?
In the case that no permissions were set for a function using `addPermission`, the function `getRoleOfPermission` will return 0 weights (instead of perhaps reverting), because looking up an uninitialized storage slot returns 0.
Because of the first issue, anyone can obtain a valid signature with 0 weights by passing an empty signature.
3. The third issue is not actually a problem in a smart contract’s code; it is a problem in the installation of a module.
When using the wallet’s interface to enable the ERC-4337 module, what happens on-chain is it called addHook 4 times to add its functionality. What it doesn’t do is call addPermission.
This would be fine if the added functions were not privileged “onlySelf” functions.
The ERC-4337 module contract source code is not published, but after running it through the debaub decompiler we can see the following privileged onlySelf function that is enabled in one of the 4 addHook calls:
When cleaned up, this reveals itself to be a “setEntrypoint” function:
This function allows updating the ERC-4337 EntryPoint contract that it trusts.
If we have control to change the EntryPoint address, we effectively gain complete control over the wallet. As the EntryPoint is the only place where `validateUserOp` happens, or maliciously does not happen before executing the transaction.
How can an attacker combine these issues into a fully working exploit?
- Submit a userOperation to the wallet with an empty signature, which calls the setEntrypoint function on the wallet to set the EntryPoint to an address they control
- Using that address, they can then call the execution function (0x226fbf04) on the wallet to execute any call without any permission validation.
To validate the finding, we simulated a transaction that implemented the first step from the above list in order to successfully set the EntryPoint on a deployed UniPass wallet: https://www.tdly.co/shared/simulation/8ecf030b-6a86-4723-9807-1519a59e9e50
The remediation
Initially, we thought that UniPass would need to somehow contact each owner of a wallet that enabled the ERC-4337 module and ask them to perform a “security update.”
Upon further consideration, we realized that it was also possible to conduct a whitehat operation to patch all the vulnerable wallets by being the first to exploit the vulnerability.
For instance, one can deploy a “rescue” contract that loops over all affected wallets, for each one:
- Set the EntryPoint to be the deployed “rescue” contract
- Now, acting as the EntryPoint, execute a transaction that
- Restores the EntryPoint to its original value
- Calls addPermission to add the missing permission to 0x2c4045b4 (setEntrypoint)
In under 24 hours from confirming receipt of the initial disclosure, the UniPass team promptly executed the white hat operation successfully, patching all vulnerable wallets, and also added the missing `addPermission` call for future enablements of the ERC-4337 module.
Modular Account Abstraction Wallets
With the increasing momentum of ERC-4337 and as AA wallets are rapidly being developed, wallet developers are realizing that having a safe and interoperable set of AA modules is key to a thriving ecosystem, and that is not a simple task.
Some initiatives have already sprung up to address this issue and others, such as ERC-6900 (Modular Smart Contract Accounts and Plugins), championed by Alchemy, are still being actively discussed and modified. ZeroDev’s founder has already committed to making their smart contract wallet compatible with the ERC-6900 standard once it’s finalized.
Safe (formerly Gnosis Safe) has also published their Safe{Core} Protocol Whitepaper in August which aims to explicitly integrate ERC-6900 with other complementary initiatives in order to solve the “wicked problem” of modular smart accounts. To solve the security issue, the approach Safe and Rhinestone are taking is to create a Module Registry where different entities can curate modules and vouch for their security.
We hope to see these initiatives mature as they will make the space more secure.
Summary
Account abstraction, specifically ERC-4337, is one of the hottest and most interesting technologies in the Ethereum blockchain ecosystem, and it bears a lot of promise for future improvements for products and end users. The Ethereum ecosystem is in the early stages of the adoption of this technology, both in terms of functionality and in terms of fortifying the security of such products.
We thank the UniPass team for their positive collaboration, and for mitigating this issue in record time.