Platform: Code4rena
Start Date: 15/12/2023
Pot Size: $38,500 USDC
Total HM: 15
Participants: 5
Period: 6 days
Judge: hansfriese
Total Solo HM: 8
Id: 313
League: ETH
Rank: 1/5
Findings: 6
Award: $0.00
π Selected for report: 4
π Solo Findings: 1
π Selected for report: rvierdiiev
Also found by: sashik_eth
Data not available
https://github.com/code-423n4/2023-12-initcapital/blob/main/contracts/core/InitCore.sol#L191-L195
Using setPosMode
function owner of position can change it's mode. When the function is called, then there are a lot of checks, like if current mode allows to decollateralize and if new mode allows to collateralize.
Also it's checked, that all position collateral is used by the new mode. It's done for the pools and for the wLp tokens.
In order to be able to use wLp tokens as collateral, then wLp should be whitelisted. It is checked in several places in the code, like here. It's also possible that after some time wLp token will be blacklisted. In this case it should not be allowed to migrate blacklisted wLp token to the new mode, however there is no such check in the setPosMode function.
As result user can provide blacklisted collateral to the new mode. I understand that borrowing factor for such collateral will be likely about 0, however if you would try to collateralize such token, then it will be denied, thus setMode function breaks this invariant.
Non whitelisted collateral can be moved to the new mode.
VsCode
Do not allow user to move blacklisted collateral to the new mode.
Error
#0 - sashik-eth
2023-12-21T23:31:51Z
Dup of #32
#1 - c4-judge
2023-12-22T03:15:23Z
hansfriese marked the issue as primary issue
#2 - c4-sponsor
2023-12-27T13:29:15Z
fez-init (sponsor) confirmed
#3 - fez-init
2023-12-27T13:29:28Z
Will add whitelist check
#4 - c4-judge
2023-12-28T16:35:14Z
hansfriese marked the issue as satisfactory
#5 - c4-judge
2023-12-28T16:35:19Z
hansfriese marked the issue as selected for report
π Selected for report: rvierdiiev
Data not available
MoneyMarketHook allows user to chain some actions into one multicall to the InitCore. In the end user can get all wrapped native tokens that he withdrew in a form of native token. Note, that this part of code withdraws all balance from wrapped token and the sends all balance to the msg.sender
. In case if balance of contract is 0, then the call will still succeed.
One type of actions that caller can do using execute
function is withdraw. In case if caller needs to repay funds to other address then he can provide it as to
param. So as result, IInitCore.burnTo
will transfer pool tokens to the provided recipient. And in case if token has a hook, like erc777 or erc677, then receiver will be triggered and he has execution control now.
User can have multiple withdraws in same multicall. And it's possible that first withdraw is wrapped native token withdraw(which user would like to receive as native) and next withdraw is with erc777 token and other recipient.
In such case, when first withdraw is done, then wrapped token is already on MoneyMarketHook balance. And then when second withdraw is handled and attacker get hook, then he can call MoneyMarketHook.execute(it doesn't have reentrancy check) again with any params that just should pass and _params.returnNative
as true. Then all wrapped token balance will be sent to the attacker and then execution will return back to the victim and it will send 0 amount as native token to the victim.
As result attacker is able to steal user's native tokens.
From readme it's clear that only fee on transfer tokens are not supported and erc777 are supported:
Please list specific ERC20 that your protocol is anticipated to interact with. Could be "any" (literally anything, fee on transfer tokens, ERC777 tokens and so forth) or a list of tokens you envision using on launch. No fee-on-transfer tokens
It's possible to steal user's funds.
VsCode
Add reentrancy check to the execute
function.
Error
#0 - c4-judge
2023-12-22T02:26:56Z
hansfriese marked the issue as primary issue
#1 - c4-sponsor
2023-12-27T13:14:05Z
fez-init marked the issue as disagree with severity
#2 - fez-init
2023-12-27T13:17:32Z
This should be a medium issue. There are multiple things that needs to be aligned, including
to
contract for the attack to happen.#3 - fez-init
2023-12-27T13:18:11Z
We will add reentrancy check to the execute function to prevent this kind of scenario anyways.
#4 - c4-sponsor
2023-12-27T13:20:54Z
fez-init (sponsor) confirmed
#5 - hansfriese
2023-12-28T02:11:40Z
I agree Medium is appropriate due to this requirement. - the victim needs to specify a certain malicious to
contract for the attack to happen.
#6 - c4-judge
2023-12-28T02:11:47Z
hansfriese marked the issue as satisfactory
#7 - c4-judge
2023-12-28T02:11:54Z
hansfriese changed the severity to 2 (Med Risk)
#8 - c4-judge
2023-12-28T02:12:15Z
hansfriese marked the issue as selected for report
π Selected for report: rvierdiiev
Data not available
https://github.com/code-423n4/2023-12-initcapital/blob/main/contracts/core/InitCore.sol#L535
TRST-M-8 from previous audit describes the fact, that when repaying is paused, then pool still continue accruing interests. Usually this is not considered as a medium bug anymore. However, protocol team has stated, that they have fixed everything.
I should say, that TRST-M-8 still exists and in case i repayment will be paused and user will not be able to reduce their debt, their debt shares will continue to accrue interest.
Interest accruing is not paused, when repaying is not allowed.
VsCode
You can implement the logic that will pause all interest accruing as well, but i am not sure this is indeed needed.
Error
#0 - c4-judge
2023-12-22T03:08:38Z
hansfriese marked the issue as primary issue
#1 - c4-sponsor
2023-12-27T10:51:25Z
fez-init (sponsor) acknowledged
#2 - fez-init
2023-12-27T10:52:44Z
There might have been miscommunications with this issue being resolved. This issue from Trust should be communicated as acknowledged.
#3 - hansfriese
2023-12-28T16:38:39Z
According to the sponsor's comment, it's worth keeping it as a valid medium.
#4 - c4-judge
2023-12-28T16:38:45Z
hansfriese marked the issue as satisfactory
#5 - c4-judge
2023-12-28T16:38:49Z
hansfriese marked the issue as selected for report
π Selected for report: rvierdiiev
Also found by: 0x73696d616f, ladboy233
Data not available
https://github.com/code-423n4/2023-12-initcapital/blob/main/contracts/core/InitCore.sol#L275
When users deposit wLP tokens as collateral, then they are checked to be whitelisted.
Later, it's possible that for some reason wLP token will be backlisted by governor. And once it's done, then users, who already used that wLP tokens as collateral will not be able to withdraw them.
Also same thing exists for the liquidateWLp
function, which means that in case if position, that is collateralized with wLP that is blacklisted, will become unhealthy, then liquidators will not be able to liquidate it.
Sponsor said that blacklisting flow will be as following.
Considering this fact i realize that for liquidation this will not be an issue as wLp will have 0 collateralization power when it will be blacklisted. However it's still possible that some user will not decollateralize their wLp tokens yet for some reasom and thus they will not be able to withdraw them later.
User can't withdraw previously deposited wLP tokens after they were blacklisted.
VsCode
Even if wLP token is backlisted now, you still should allow user to withdraw them. After all you have health check function that will guarantee that position has enough collateral.
Error
#0 - c4-judge
2023-12-22T03:03:03Z
hansfriese marked the issue as primary issue
#1 - c4-sponsor
2023-12-27T13:11:20Z
fez-init (sponsor) acknowledged
#2 - fez-init
2023-12-27T13:11:45Z
We will use unwhitelisting with care.
#3 - c4-judge
2023-12-28T16:43:29Z
hansfriese marked the issue as satisfactory
#4 - c4-judge
2023-12-28T16:43:34Z
hansfriese marked the issue as selected for report
π Selected for report: ladboy233
Also found by: rvierdiiev
Data not available
https://github.com/code-423n4/2023-12-initcapital/blob/main/contracts/core/InitCore.sol#L288
In case if borrower's position is unhealthy, then he can be liquidated. Liquidator can provide amount of shares in _poolToRepay
that he will cover and expects to get back _poolOut
shares. It is possible that position created a bad debt. This means that amount that position has borrowed is bigger than supplied collateral.
In this case only part of debt of the positon will be repaid to lenders by liquidator. Let's check what that means for the pool.
When burn
is called, then _toAmt
is called to calculate amount that user can receive for his shares. It uses cash + totalDebt
and totalSupply
to calculate it. totalDebt
is all borrowed amount that is not repaid yet. So contract expects that all borrowed amount will be repaid eventually.
So in case if bad debt occurs it means that part of borrowed amount will not be received back by LendingPool contract, however contract still calculates assets using outdated data.
As result this bad debt will create contract insolvency, which means that contract will not have enough balance to pay last burners.
Bad debt is not distributed among all lenders
You should track when position is closed with bad debt and then notify LendingPool contract that borrower will not be able to return part of funds. This should decrease totalDebt
amount, which will decrease share price and thus distribute that debt among all lenders.
Error
#0 - c4-judge
2023-12-22T02:35:22Z
hansfriese marked the issue as duplicate of #9
#1 - fez-init
2023-12-27T10:47:01Z
@hansfriese This issue is different from #9 .
#2 - hansfriese
2023-12-28T07:15:09Z
@fez-init
Would you explain in detail what the differences are?
From my understanding, both issues are saying totalDebt
should be updated properly by distributing a debt among all lenders when a position is closed with a bad debt.
#3 - fez-init
2023-12-28T22:47:57Z
@hansfriese This issue talks about a recommendation where bad debt should be socialized to all lenders.
#9 talks about the case of tx revert when bad debt occurs. When bad debt occurs, what will likely happen is:
share > 0
so the secondary liquidation will always undesirably revert.#4 - c4-sponsor
2023-12-28T22:48:13Z
fez-init marked the issue as disagree with severity
#5 - fez-init
2023-12-28T22:49:08Z
This issue should be marked as part of low or QA since it is more of a recommendation to the design choice.
#6 - c4-sponsor
2023-12-28T23:04:56Z
fez-init (sponsor) acknowledged
#7 - hansfriese
2023-12-29T06:39:57Z
Downgrade to QA as it doesn't show the main impact.
#8 - c4-judge
2023-12-29T06:40:03Z
hansfriese marked the issue as not a duplicate
#9 - c4-judge
2023-12-29T06:40:10Z
hansfriese changed the severity to QA (Quality Assurance)
#10 - c4-judge
2023-12-30T04:26:37Z
hansfriese marked the issue as grade-c
#11 - rvierdiyev
2024-01-03T08:26:52Z
hello @hansfriese
I understand that #9 moves 1 step further and discovers that liquidation is not possible when position was liquidated and bad debt have occured. However i do not agree that this report doesn't show the main impact
. Because for me the main impact is not disability to repay bad debt loan by anyone else, but the main impact is system insolvency.
While i agree that protocol is able(and likely will) to repay some bad debt, i didn't see any solution from protocol side to do that. I mean that in case of big amount of bad debt, it can be not enough just to use protocol's fee as protocol fee is not guaranteed to stay in the contracts and can be withdrawn at any time.
Insolvency was always bigger than qa, that's why i believe this is medium severity issue.
#12 - hansfriese
2024-01-04T15:10:25Z
@rvierdiyev I totally understand your point.
#13 - c4-judge
2024-01-04T15:11:11Z
hansfriese removed the grade
#14 - c4-judge
2024-01-04T15:11:26Z
This previously downgraded issue has been upgraded by hansfriese
#15 - c4-judge
2024-01-04T15:11:26Z
This previously downgraded issue has been upgraded by hansfriese
#16 - c4-judge
2024-01-04T15:11:38Z
hansfriese marked the issue as duplicate of #9
#17 - c4-judge
2024-01-04T15:11:45Z
hansfriese marked the issue as partial-50
#18 - c4-judge
2024-01-04T15:11:51Z
hansfriese marked the issue as satisfactory
#19 - c4-judge
2024-01-04T15:16:11Z
hansfriese marked the issue as partial-50
π Selected for report: ladboy233
Also found by: rvierdiiev
Data not available
https://github.com/code-423n4/2023-12-initcapital/blob/main/contracts/core/InitCore.sol#L462
Issue TRST-M-1
from previous audit still exist.
In order to calculate collateral amount getCollateralCreditCurrent_e36
function is used.
https://github.com/code-423n4/2023-12-initcapital/blob/main/contracts/core/InitCore.sol#L462
uint tokenValue_e36 = ILendingPool(pools[i]).toAmtCurrent(shares[i]) * tokenPrice_e36;
tokenValue_e36
is usd value of user's shares in the pool. To calculate amount that pool will return for the shares toAmt
function is called and this function will use totalAssets()
to calculate output amount. totalAssets()
is cash + totalDebt
.
In case if syncCash
is called, then cash
is updated with contract balance.
syncCash
is called by InitCore.flash
function, which means that it's enough for attacker to get a small flash loan then donate tokens to the pool and syncCash
will update cahs
varible and as result will increase his collateral.
Thus, issue still exists.
Also in similar way poolConfig.supplyCap
can be breached, however i don't see issue in this case as it can be breached even non maliciously just with accrued interest adn flash fees.
It's possible to add more collateral, even when collateralization is paused.
VsCode
Don't see how to fix this correctly, maybe change flash repayment flow, so flash loaner needs to approve amount to the init core and core will then send tokens with fee to the pool.
Error
#0 - c4-judge
2023-12-22T03:07:51Z
hansfriese marked the issue as duplicate of #3
#1 - c4-judge
2023-12-29T06:59:48Z
hansfriese marked the issue as satisfactory