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

Contract Balance Manipulation Vulnerability

Summary

The withdrawInheritedFunds function related to the use of address(this).balance. This vulnerability allows attackers to manipulate the contract's ETH balance through various techniques, potentially leading to incorrect fund distribution and unfair allocation to beneficiaries.

Vulnerability Details

Description

The function withdrawInheritedFunds distributes ETH to beneficiaries by calculating each recipient's share based on the contract's current balance:

uint256 ethAmountAvailable = address(this).balance;
uint256 amountPerBeneficiary = ethAmountAvailable / divisor;

Unfortunately, address(this).balance can be manipulated in several ways by malicious actors:

  1. Using selfdestruct(address) to forcibly send ETH to the contract

  2. Pre-sending ETH to a contract address before deployment

  3. Miner/validator manipulation of coinbase address payments

An attacker can exploit this by manipulating the balance immediately before withdrawal execution, causing:

  • Dilution of beneficiary shares if artificially inflated

  • Potential gas-related issues with unexpected amounts

  • Possible rounding issues leaving dust amounts trapped

Code Location

function withdrawInheritedFunds(address _asset) external {
// ...
if (_asset == address(0)) {
uint256 ethAmountAvailable = address(this).balance;
uint256 amountPerBeneficiary = ethAmountAvailable / divisor;
// ...
}
// ...
}

Impact

This vulnerability can directly lead to financial loss for legitimate beneficiaries.

Tools Used

Recommendations

Use an internal accounting system instead of relying on address(this).balance:

Alternatively, implement a pull-pattern where beneficiaries withdraw their own funds:

// Map beneficiaries to their entitled amounts
mapping(address => uint256) public ethShares;
// Set the shares when inheritance is triggered
function triggerInheritance() external {
// Verify conditions
isInherited = true;
uint256 divisor = beneficiaries.length;
uint256 amountPerBeneficiary = trackedEthBalance / divisor;
for (uint256 i = 0; i < divisor; i++) {
ethShares[beneficiaries[i]] = amountPerBeneficiary;
}
}
// Let beneficiaries withdraw individually
function withdrawMyShare() external {
uint256 amount = ethShares[msg.sender];
require(amount > 0, "No funds to withdraw");
ethShares[msg.sender] = 0;
(bool success,) = msg.sender.call{value: amount}("");
require(success, "ETH transfer failed");
}
Updates

Lead Judging Commences

0xtimefliez Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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