Beginner FriendlyFoundry
100 EXP
View results
Submission Details
Severity: medium
Invalid

Lack of Signature Replay Protection

Description: The contract doesn't implement protection against signature replay attacks. An attacker could intercept a valid transaction and replay it multiple times. We can see that in the function _validateTransaction

bytes32 txHash = _transaction.encodeHash();
address signer = ECDSA.recover(txHash, _transaction.signature);
bool isValidSigner = signer == owner();

Impact:

  1. Alice signs a transaction to send 1 ETH to Bob.

  2. The transaction is broadcasted and executed successfully.

  3. An attacker intercepts this transaction.

  4. The attacker repeatedly calls executeTransactionFromOutside with the intercepted transaction.

  5. The wallet executes the same transaction multiple times, potentially draining Alice's funds.

Recommended Mitigation:

Implement a nonce-based replay protection:

function _validateTransaction(Transaction memory _transaction) internal returns (bytes4 magic) {
+ require(!usedNonces[_transaction.nonce], "Nonce already used");
+ usedNonces[_transaction.nonce] = true;
SystemContractsCaller.systemCallWithPropagatedRevert(
uint32(gasleft()),
address(NONCE_HOLDER_SYSTEM_CONTRACT),
0,
abi.encodeCall(INonceHolder.incrementMinNonceIfEquals, (_transaction.nonce))
);
// Check for fee to pay
uint256 totalRequiredBalance = _transaction.totalRequiredBalance();
if (totalRequiredBalance > address(this).balance) {
revert MondrianWallet2__NotEnoughBalance();
}
// Check the signature
bytes32 txHash = _transaction.encodeHash();
address signer = ECDSA.recover(txHash, _transaction.signature);
bool isValidSigner = signer == owner();
if (isValidSigner) {
magic = ACCOUNT_VALIDATION_SUCCESS_MAGIC;
} else {
magic = bytes4(0);
}
return magic;
}
Updates

Lead Judging Commences

bube Lead Judge 12 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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