Finding a Bug in Safe's ERC-4337 Module
How ERC-4337 context exposed a paymasterAndData signature flaw that an isolated contract review missed.
On November 28 at 11 p.m. UTC+9, Safe and Pimlico announced Safe’s ERC-4337 module. As ZeroDev’s CTO and a security researcher, I always inspect the code when someone launches something related to ERC-4337. Safe’s announcement caught my attention.
When I review ERC-4337 code, I look for vulnerabilities that arise specifically from the ERC-4337 context. That context is what auditors often miss.
The missing field
That was exactly the case with Safe’s ERC-4337 module. If you only looked at the module’s smart contracts in the context of a simple smart contract wallet, there was nothing obviously vulnerable. In the ERC-4337 context, however, it became problematic.
As noted in the related blog post, the module used custom logic to calculate the hash to sign and did not include paymasterAndData. The same signature could therefore be used for different UserOperations that differed only in paymasterAndData, including one in which the field was emptied.
This meant that a user who expected a paymaster to cover the gas could end up paying for it. With an ERC-20 paymaster, I believe this could also be used to withdraw both ETH and ERC-20 tokens, although the user would first have to approve the ERC-20 paymaster.
Disclosure
I saw the announcement 90 minutes after it was published, and it took around 30 minutes to find the bug. I was nervous that the module might already have been used on mainnet. Unlike a DeFi protocol exploit, the issue could take time to mitigate if many wallets were using the module.
I immediately contacted @love_ethereum from Pimlico even though I did not yet have a proof of concept. I trusted him personally, Safe and Pimlico had announced the module together, and I initially thought Pimlico had built it.
A group was set up an hour later. The Safe team understood the issue immediately even without a proof of concept, and the code was patched the next day. I researched whether any wallets had been affected, and the Safe team did the same.
Lessons
- An audit does not make code bulletproof.
- Understanding the surrounding context is critical when looking for bugs.
- Asking another team in the same domain for feedback may produce better feedback than an audit report.
- Reading a lot of code matters.
For auditors and bug bounty hunters, focusing on a specific area of smart contracts can be a way to outperform generalists.