Broad Grey Dragon
Medium
https://github.com/sherlock-audit/2024-12-ethos-update/blob/main/ethos/packages/contracts/contracts/ReputationMarket.sol#L480 The current code adds the full purchaseCostBeforeFees to the marketFunds[profileId] without considering the protocol fee and donation, which are deducted later in the function. This leads to an incorrect state of marketFunds, as it does not reflect the actual funds added to the market after fees.
marketFunds[profileId] += purchaseCostBeforeFees;
Cause: The funds are added to marketFunds before subtracting the protocol fee and donation, leading to an inflated marketFunds value. Nature of the Issue: The marketFunds reflects more ETH than it should because the fees (protocol fee and donation) are not accounted for when updating it.
Incorrect Accounting: marketFunds[profileId] will incorrectly track the funds in the market, as it will reflect the full amount before fees are deducted. This could cause inconsistencies in the contract's financial data.
// Assume ReputationMarket.sol has already been deployed
contract ExploitReputationMarket {
ReputationMarket reputationMarket; // Reference to the ReputationMarket contract
// Constructor to set the ReputationMarket contract address
constructor(address _reputationMarket) {
reputationMarket = ReputationMarket(_reputationMarket);
}
// Exploiting the vulnerability by sending more ETH than needed
function exploitBuyVotes(uint256 profileId, uint256 maxVotesToBuy, uint256 minVotesToBuy) external payable {
uint256 amountSent = msg.value; // Store the amount sent by the attacker
// Call buyVotes function, which will attempt to buy votes and potentially refund excess ETH
reputationMarket.buyVotes{value: amountSent}(
profileId,
true, // Buy trust votes
maxVotesToBuy,
minVotesToBuy
);
// Malicious actor may attempt to manipulate the marketFunds state by exploiting refund logic
// If any refund is issued, the state of marketFunds might not be accurately updated
}
// Function to check the current marketFunds of a profile
function getMarketFunds(uint256 profileId) external view returns (uint256) {
return reputationMarket.marketFunds(profileId);
}
}
The attacker deploys an ExploitReputationMarket contract and links it to the deployed ReputationMarket contract.
The attacker calls the buyVotes function of the ReputationMarket contract. The attacker sends more ETH than required, which triggers a refund logic where the excess funds are returned to the attacker.
Due to the improper handling of the refund process (especially the state update of marketFunds after the refund), the contract's internal marketFunds balance may get incorrectly updated. The contract’s state is manipulated, and the marketFunds balance may not reflect the actual transaction, potentially leading to incorrect balances that can be exploited.
Ensure that the state of marketFunds is correctly updated after every transaction, including refunds. Use checks to validate that the transaction amount, fees, and refunds are correctly handled and consistently updated in the state.