Company Simulator

First Flight #51
Beginner FriendlyDeFi
100 EXP
View results
Submission Details
Impact: high
Likelihood: medium
Invalid

pay_holding_debt() allows owner to reset debt accounting and manipulate solvency

Root + Impact

Description

  • Normal behavior:

    If the amount exceeds the owed debt, the excess is added to company_balance.

    The pay_holding_debt() function lets the owner pay down the company’s accumulated holding_debt by sending ETH to the contract.

  • Specific issue: Because the owner directly controls both debt reduction and balance increment, this function can be used to manipulate solvency metrics.

    By temporarily setting holding_debt = 0 and inflating company_balance, the owner can make the company appear solvent — allowing new investments or withdrawals even though true operational debt remains unpaid.

// Root cause in the codebase with @> marks to highlight the relevant section
@payable
@external
def pay_holding_debt():
...
@> if msg.value >= self.holding_debt:
@> excess: uint256 = msg.value - self.holding_debt
@> self.holding_debt = 0
@> self.company_balance += excess

Risk

Likelihood:

1.Medium — Can happen anytime the owner wants to manipulate metrics or reset solvency before audits or before accepting new investor funds.

2.Only the owner can call the function, but as a privileged actor, they might exploit it to mislead external parties.

Impact:

  • High — Breaks trust and accounting consistency:

  • The owner can artificially increase solvency and reopen investment even when the company is underwater.

  • Subsequent investors may lose funds due to false financial reporting.

  • Potential to drain investor capital through manipulation.

Proof of Concept

Explanation:

By paying more ETH than the debt owed, the owner resets holding_debt to zero and inflates company_balance.

This makes the company appear fully solvent and profitable — even if prior operational losses exist — enabling fraudulent investment or withdrawal operations.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/*
PoC: Demonstrates owner solvency manipulation through pay_holding_debt().
*/
interface IVulnerable {
function pay_holding_debt() external payable;
function get_share_price() external view returns (uint256);
}
contract DebtManipulation {
IVulnerable target;
address owner;
constructor(address _target) {
target = IVulnerable(_target);
owner = msg.sender;
}
function fakeSolvency() external payable {
// Step 1: assume holding_debt = 100 ETH, company_balance = 10 ETH
// Step 2: owner pays minimal ETH to appear solvent
target.pay_holding_debt{value: 100 ether}();
// Step 3: now company_balance increased, debt = 0, making share_price look inflated
uint256 price = target.get_share_price();
require(price > 0, "Fake solvency succeeded");
}
}

Recommended Mitigation

Explanation (brief)

Add stricter accounting validation for debt payments and emit detailed events for transparency.

Prevent overpayment from being counted as operational balance — instead, route it separately or require explicit acknowledgment.

- remove this code
+ add this code
@payable
@external
def pay_holding_debt():
assert msg.sender == OWNER, "Not the owner!!!"
assert self.holding_debt > 0, "No debt to pay"
-
- if msg.value >= self.holding_debt:
- excess: uint256 = msg.value - self.holding_debt
- self.holding_debt = 0
- self.company_balance += excess
- else:
- self.holding_debt -= msg.value
+ payment: uint256 = msg.value
+ if payment >= self.holding_debt:
+ # Limit payment strictly to debt owed; excess returned
+ excess: uint256 = payment - self.holding_debt
+ self.holding_debt = 0
+ if excess > 0:
+ raw_call(msg.sender, b"", value=excess, revert_on_failure=True)
+ else:
+ self.holding_debt -= payment
+
+ # Log accurate repayment event for transparency
+ log DebtRepaid(payer=msg.sender, amount=payment)
Updates

Lead Judging Commences

0xshaedyw Lead Judge
7 days ago
0xshaedyw Lead Judge 5 days ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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