Description
Github username: @obingo31
Twitter username: --
Submission hash (on-chain): 0xe89620ff010e672c753b01833e787f6db5c8efacf602e86b726a06174f704afb
Severity: high
Description:
Description
The _validateSignature
function in the AtomWallet
contract is responsible for validating the signatures of user operations. However, there is a potential replay attack vulnerability due to the lack of nonce
handling or unique operation identifiers within the signature verification process. This vulnerability allows an attacker to reuse a valid signature for multiple transactions, bypassing the intended authorization checks. The vulnerability also allows an attacker to potentially replay a valid user operation multiple times, leading to unintended consequences such as double spending or manipulating internal accounting.
Attack Scenario
The legitimate owner of the wallet signs a UserOperation with a specific userOpHash and submits it for execution.
The transaction is successfully executed, and the signature is deemed valid.
Replay Attack:
An attacker obtains the userOpHash
and the corresponding valid signature from the previous transaction.
The attacker resubmits the same UserOperation
with the identical userOpHash and signature.
The _validateSignature
function verifies the signature as valid because the userOpHash
is the same and was previously signed by the legitimate owner.
The transaction is executed again, allowing the attacker to perform unauthorized actions without the owner's consent.
Attachments
- Proof of Concept (PoC) File
Revised _validateSignature function
function _validateSignature(UserOperation calldata userOp, bytes32 userOpHash)
internal
virtual
override
returns (uint256 validationData)
{
bytes32 hash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", userOpHash, userOp.nonce));
(address recovered,,) = ECDSA.tryRecover(hash, userOp.signature);
if (recovered != owner() || userOp.nonce <= usedNonces[recovered]) {
return SIG_VALIDATION_FAILED;
}
usedNonces[recovered] = userOp.nonce + 1; // Update used nonces after successful validation
return 0;
}
// fix
mapping(address => uint256) public usedNonces;
-
Added a new field 'nonce' to UserOperation struct (not shown here)
-
Included 'nonce' in the data hashed before signature verification
-
Added check for 'nonce' after signature verification
- Checks if the 'nonce' is greater than the last used nonce for the signer address
- Maintains a mapping 'usedNonces' to track used nonces
-
Updates 'usedNonces' after successful validation to prevent replaying the same operation
-
Revised Code File (Optional)
We recommend implementing the suggested fix or a similar approach to mitigate replay attacks in the_validateSignature
function. This will significantly enhance the security of the smart contract and prevent attackers from exploiting this vulnerability.