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

Lack of gas limit in MondrianWallet2::_executeTransaction poses risk of gas depletion attack

Summary

The MondrianWallet2::_executeTransaction function lacks a defined gas limit for transaction execution, potentially allowing malicious actors to construct transactions with computationally expensive operations.

This oversight can lead to a gas depletion attack, where maliciously crafted transactions consume excessive gas, thereby blocking or delaying the execution of legitimate transactions on the network.

Vulnerability Details

  1. Craft a transaction with complex data, such as a large byte array.

  2. Attempt to execute the transaction on the MondrianWallet2 contract.

  3. Observe the transaction fail due to gas exhaustion, indicating the vulnerability to denial-of-service attacks through gas depletion.

To simulate realistic conditions similar to mainnet and testnet, we can set a gas limit of around 12 to 15 million for our tests.

Proof of Code

Copy the following test in the test suite.

Execute it with the command forge test --mt testDenialOfService --gas-limit 15000000 . 15.000.000 being a realistic gas limit.

function testDenialOfService() public {
// Arrange
// Define complex data
bytes memory complexData = new bytes(10000); // Large byte array
// Fill with arbitrary data
for (uint256 i = 0; i < 10000; i++) {
complexData[i] = bytes1(uint8(i % 256));
}
HeavyMaliciousContract heavyContract = new HeavyMaliciousContract();
address dest = address(heavyContract);
uint256 value = 0;
bytes memory functionData = abi.encodeWithSignature(
"heavyComputationFunction(bytes)",
complexData
);
// Create a transaction with high gas limits and complex data
Transaction memory costlyTransaction = _createUnsignedTransaction(
address(this),
113, // Transaction type
dest,
value,
functionData
);
uint256 realisticGasLimit = 15_000_000;
uint256 initialGas = gasleft();
vm.prank(mondrianWallet.owner());
vm.expectRevert();
mondrianWallet.executeTransaction(
EMPTY_BYTES32,
EMPTY_BYTES32,
costlyTransaction
);
uint256 finalGas = gasleft();
uint256 gasUsed = initialGas - finalGas;
assert(gasUsed <= realisticGasLimit);
}

Impact

This attack can disrupt protocol operations, leading to transaction delays and failures, financial losses, and user dissatisfaction. It can also contribute to network congestion and damage the contract's reputation.

Tools Used

Manual review

Recommendations

Consider setting a gas limit inside the MondrianWallet2::_executeTransaction function:

function _executeTransaction(Transaction memory _transaction) internal {
+ // Adjust this treshold based on testing
+ uint256 gasLimitThreshold = 2000000;
address to = address(uint160(_transaction.to));
uint128 value = Utils.safeCastToU128(_transaction.value);
bytes memory data = _transaction.data;
if (to == address(DEPLOYER_SYSTEM_CONTRACT)) {
uint32 gas = Utils.safeCastToU32(gasleft());
SystemContractsCaller.systemCallWithPropagatedRevert(
gas,
to,
value,
data
);
} else {
bool success;
- (success, ) = to.call{value: value}(data);
+. (success, ) = to.call{value: value, gas: gasLimitThreshold}(data);
if (!success) {
revert MondrianWallet2__ExecutionFailed();
}
}
}
Updates

Lead Judging Commences

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

Support

FAQs

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