The MErc20DelegateFixer
contract inherits from MErc20Delegate
which inherits a hierarchy of contracts including MToken
. While the MErc20DelegateFixer
contract mentions a nonReentrant
modifier, it relies on the inheritance chain for reentrancy protection. This audit report identifies a potential reentrancy vulnerability in the following functions:
repayBadDebtWithCash
repayBadDebtWithReserves
The repayBadDebtWithCash
and repayBadDebtWithReserves
functions are vulnerable to reentrancy attacks because they lack an explicit nonReentrant
modifier within the functions themselves. Here's why relying solely on inheritance is risky:
Modifier Placement: The nonReentrant
modifier might be placed in the parent contract (MToken) but not necessarily applied to every function. Even if the parent contract has the modifier, it might not be enough if the vulnerable function in the child contract (MErc20DelegateFixer) doesn't inherit it explicitly.
An attacker could exploit this vulnerability by calling the function recursively within the same transaction, manipulating the bad debt counter and potentially stealing user funds.
Here's a specific scenario of how the attack might work for repayBadDebtWithCash
:
Attacker initiates a transaction calling repayBadDebtWithCash
with a certain amount (X) to be repaid.
Within the repayBadDebtWithCash
function:
The function calls transferFrom
to withdraw X amount of tokens from the msg.sender (user) to the contract.
Before the transferFrom
call completes (funds not yet transferred), the attacker calls a malicious contract function from another address.
The malicious contract function:
Re-enters the repayBadDebtWithCash
function itself recursively.
Within the re-entered call, the attacker manipulates the badDebt
state variable to a higher value (Y) greater than X. This can be done by providing a manipulated input or exploiting other logic vulnerabilities in the contract.
The initial call to repayBadDebtWithCash
continues:
The function subtracts the initial amount X (intended repayment) from the inflated bad debt value Y, resulting in a bad debt reduction of only (Y - X).
Since the transferFrom
has already been called successfully, the user's X amount is transferred to the contract.
In this scenario, the attacker achieves a double spend:
The bad debt is only reduced by (Y - X), leaving a higher bad debt than intended.
The attacker steals the user's X amount transferred to the contract through transferFrom
.
A similar attack scenario can be constructed for the repayBadDebtWithReserves
function.
A successful reentrancy attack could allow an attacker to:
Steal user funds intended for bad debt repayment.
Reduce the bad debt counter by a smaller amount than intended, leaving a higher bad debt burden.
Disrupt the normal operation of the contract by manipulating reserve levels.
manual code review
use openzepplin reentrancyGuard
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.