PositionManager.sol#permit() will fail to validate signatures from counterfactual wallets
Impact
This vulnerability impacts PositionManager.sol#premit() ability to validate signatures for counterfactual ERC-4337 accounts, limiting the usability for users of certain wallets that rely on AA.
Proof of Concept
EIP 1271 allows contracts to sign messages and works great in tandem with EIP 4337 (account abstraction).
As we know, in ERC-4337, the account is not deployed until the first UserOp is mined. Before then, the account exists "counterfactually" — it has an address even though it's not really deployed. Usually, this is great since we can use the counterfactual address to receive assets without deploying the account first.
However, if the user wants to sign a message for a permit for PositionManager, but his wallet currently exists "counterfactually" this becomes an issue since the PositionManger.pause is going to look at the user address, see that it has no code, and assume that the user is EOA, and reject the signature.
Since the contract isn't there yet, it wouldn't know to validate the staker signature through ERC-1271
This practically means PositionManager will fail to validate signatures for users of notorious wallets/projects, including Safe, Sequence, and Argent supporting ERC1271, but also ERC4337 wallets, even though they intend to support signatures by EIP1271 compliant wallets, as confirmed by these tests.
Given that the protocol decided to support contract-based wallets (that support ERC4337) and implement ERC1271, my assumption is that they "inherit" the possibility from the wallet providers to support ERC4337 too.
This issue may seem like a problem with ERC4337 or EIP1271. Still, it stems from the fact that protocol is taking responsibility to check the validity of signatures, but partially failing to trigger signature validation signatures for a group of wallets from a provider (the validation will succeed if the ERC4337 wallet is deployed).
Thankfully, as of today, EIP-6492 solves this issue. The author of the EIP already implemented ERC-6492 in a universal library which can verify 6492, 712, and 1271 sigs with this pull request.
ERC6492 assumes that the signing contract will normally be a contract wallet, but it could be any contract that implements ERC-1271 and is deployed counterfactually.
If the contract is deployed, produce a normal ERC-1271 signature
If the contract is not deployed yet, wrap the signature as follows: concat(abi.encode((create2Factory, factoryCalldata, - originalERC1271Signature), (address, bytes, bytes)), magicBytes)
That works because, as defined in the EIP, the wallet should return the magic value in both cases.
If that doesn't work for you, I would advise clarifying in the docs and the contract itself that permit doesn't support counterfactual ERC4337 accounts.
Lines of code
https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-core/src/base/PermitERC721.sol#L100
Vulnerability details
PositionManager.sol#permit()
will fail to validate signatures from counterfactual walletsImpact
This vulnerability impacts
PositionManager.sol#premit()
ability to validate signatures for counterfactualERC-4337
accounts, limiting the usability for users of certain wallets that rely on AA.Proof of Concept
EIP 1271
allows contracts to sign messages and works great in tandem with EIP 4337 (account abstraction).As we know, in
ERC-4337
, the account is not deployed until the first UserOp is mined. Before then, the account exists "counterfactually" — it has an address even though it's not really deployed. Usually, this is great since we can use the counterfactual address to receive assets without deploying the account first.However, if the user wants to sign a message for a
permit
forPositionManager
, but his wallet currently exists "counterfactually" this becomes an issue since thePositionManger.pause
is going to look at the user address, see that it has no code, and assume that the user is EOA, and reject the signature.Since the contract isn't there yet, it wouldn't know to validate the staker signature through ERC-1271
This practically means
PositionManager
will fail to validate signatures for users of notorious wallets/projects, including Safe, Sequence, and Argent supporting ERC1271, but alsoERC4337
wallets, even though they intend to support signatures byEIP1271
compliant wallets, as confirmed by these tests.Given that the protocol decided to support contract-based wallets (that support
ERC4337
) and implementERC1271
, my assumption is that they "inherit" the possibility from the wallet providers to supportERC4337
too.This issue may seem like a problem with
ERC4337
orEIP1271
. Still, it stems from the fact that protocol is taking responsibility to check the validity of signatures, but partially failing to trigger signature validation signatures for a group of wallets from a provider (the validation will succeed if theERC4337
wallet is deployed).Tools Used
Recommended Mitigation Steps
Thankfully, as of today, EIP-6492 solves this issue. The author of the EIP already implemented ERC-6492 in a universal library which can verify 6492, 712, and 1271 sigs with this pull request.
ERC6492
assumes that the signing contract will normally be a contract wallet, but it could be any contract that implementsERC-1271
and is deployed counterfactually.That works because, as defined in the EIP, the wallet should return the magic value in both cases. If that doesn't work for you, I would advise clarifying in the docs and the contract itself that
permit
doesn't support counterfactualERC4337
accounts.Assessed type
Other