Below are the steps to check this vulnerability.
Proof of Code
Create a new smart contract in `contracts` folder called `MondrianWalletHarness.sol` to enable calling `_validateSignature` internal function with the following code:
pragma solidity 0.8.24;
import {MondrianWallet, PackedUserOperation} from "./MondrianWallet.sol";
contract MondrianWalletHarness is MondrianWallet {
constructor(address entryPoint) MondrianWallet(entryPoint) {}
function validateSignature(
PackedUserOperation calldata userOp,
bytes32 userOpHash
) external pure returns (uint256) {
return _validateSignature(userOp, userOpHash);
}
}
Create a new file in ignition/modules
folder called MondrianModuleHarness.js
with the code:
const { buildModule } = require("@nomicfoundation/hardhat-ignition/modules")
const { networkConfig } = require("../../helper-config")
const { network } = require("hardhat")
const { MockEntryPoint } = require("./MockEntryPoint.js")
const MondrianModuleHarness = buildModule("MondrianModuleHarness", (m) => {
const chainId = network.config.chainId
let entryPointAddress
if (chainId == 1337) {
console.log("Deploying MockEntryPoint")
ignition.deploy(MockEntryPoint).then((mockEntryPoint) => {
entryPointAddress = mockEntryPoint.address
})
}
entryPointAddress = entryPointAddress || m.getParameter("entryPointAddress", networkConfig[chainId].entryPoint)
const mondrianWalletHarness = m.contract("MondrianWalletHarness", [entryPointAddress])
return { mondrianWalletHarness }
})
module.exports = MondrianModuleHarness
In MondrianWallet.test.js
file, place the following test:
it("Anyone can send operations", async function () {
const mondrianWalletHarnessDeployment = await ignition.deploy(MondrianModuleHarness)
const mondrianWalletHarness = mondrianWalletHarnessDeployment.mondrianWalletHarness
const [_, account] = await ethers.getSigners();
const message = ethers.keccak256(ethers.toUtf8Bytes("test"))
const sig = await account.signMessage(message)
const userOp = [account.address, 0, "0x", "0x", ethers.ZeroHash, 0, ethers.ZeroHash, "0x", sig]
const result = await mondrianWalletHarness.validateSignature(userOp, message)
assert.equal(result, 0)
})
Then just use yarn test
in the command line to check the result.
Any actor (EOAs or smart contracts) can perform any operations on this contract, making it vulnerable to any malicious transaction, such as:
among others.
function _validateSignature(
PackedUserOperation calldata userOp,
bytes32 userOpHash
) internal pure returns (uint256 validationData) {
bytes32 hash = MessageHashUtils.toEthSignedMessageHash(userOpHash);
- ECDSA.recover(hash, userOp.signature);
- return SIG_VALIDATION_SUCCESS;
+ address recovered = ECDSA.recover(hash, userOp.signature);
+ return owner() == recovered ? SIG_VALIDATION_SUCCESS : SIG_VALIDATION_FAILED;
}