All UserOperations provided by EntryPoint will succeed in MondrianWallet.validateUserOp() because it always returns SIG_VALIDATION_SUCESS, even if the provided UserOperation signature was created by accounts other than the owner of the wallet.
As per ERC-4337, bundlers collect UserOperations which are then packed and ultimately sent to the EntryPoint contract. The EntryPoint will then validate each UserOperation against the sender account (the smart account). To do that, smart accounts have to implement validateUserOp(), which has to return with a success or failure signal, depending on whether the given UserOperation had a valid signature.
If the provided signature is not valid, validateUserOp() needs to return an error code (1) as uint256.
MondrianWallet already makes use of a SIG_VALIDATION_SUCESS constant to signal a successful validation, however it doesn't take the failure case into account.
In fact, it doesn't even check the return value when trying to recover the signer's address. This means, any UserOperation that is sent to validateUserOp() will be considered valid, allowing malicious actors to execute any function on any contract via MondrianWallet by crafting and sending a dedicated UserOperation to the network.
The implementation of MondrianWallet.validateUserOp() can be found here, which will call _validateSignature(). Whatever _validateSignature() returns is the return value for validateUserOp().
Here's a code snippet from the source:
Notice in the code above that there's no check on ECDSA.recover(). ECDSA.recover() returns the address of the account that created the signature. According to the protocol's description, only the owner of the wallet should be able to execute UserOperations on the smart account. Since there's no check, any signature will be valid. It's also very obvious that this function always returns SIG_VALIDATION_SUCCESS.
Any account can execute transactions on behalf of the smart account. This includes functionality provided by the wallet itself (like minting Mondrian paintings), as well as any external contracts and functions that are specified in the UserOperation.
In the worst case, this can cause loss of user funds and ownership.
Manual review
Foundry to implement test case
Ensure the provided signature is properly validated by checked if the signer of a given UserOperation is indeed the owner of the smart account.
Attacker: Any account other than the owner() of the smart account
Victim: The owner() or deployer of the smart account
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.