INIT Capital Invitational - rvierdiiev's results

The Liquidity Hook Money Market -- Lend, Borrow, and Access Yield Strategies.

General Information

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

INIT Capital

Findings Distribution

Researcher Performance

Rank: 1/5

Findings: 6

Award: $0.00

🌟 Selected for report: 4

πŸš€ Solo Findings: 1

Findings Information

🌟 Selected for report: rvierdiiev

Also found by: sashik_eth

Labels

bug
2 (Med Risk)
primary issue
satisfactory
selected for report
sponsor confirmed
M-06

Awards

Data not available

External Links

Lines of code

https://github.com/code-423n4/2023-12-initcapital/blob/main/contracts/core/InitCore.sol#L191-L195

Vulnerability details

Proof of Concept

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.

Impact

Non whitelisted collateral can be moved to the new mode.

Tools Used

VsCode

Do not allow user to move blacklisted collateral to the new mode.

Assessed type

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

Findings Information

🌟 Selected for report: rvierdiiev

Labels

bug
2 (Med Risk)
disagree with severity
downgraded by judge
primary issue
satisfactory
selected for report
sponsor confirmed
edited-by-warden
M-07

Awards

Data not available

External Links

Lines of code

https://github.com/code-423n4/2023-12-initcapital/blob/main/contracts/hook/MoneyMarketHook.sol#L76-L80

Vulnerability details

Proof of Concept

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

Impact

It's possible to steal user's funds.

Tools Used

VsCode

Add reentrancy check to the execute function.

Assessed type

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

  • supporting of ERC777. We did not intend to support ERC777, but acknowledge that it may not be communicated clearly.
  • the victim needs to specify a certain malicious 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

Findings Information

🌟 Selected for report: rvierdiiev

Also found by: ladboy233, said

Labels

bug
2 (Med Risk)
primary issue
satisfactory
selected for report
sponsor acknowledged
M-08

Awards

Data not available

External Links

Lines of code

https://github.com/code-423n4/2023-12-initcapital/blob/main/contracts/core/InitCore.sol#L535

Vulnerability details

Proof of Concept

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.

Impact

Interest accruing is not paused, when repaying is not allowed.

Tools Used

VsCode

You can implement the logic that will pause all interest accruing as well, but i am not sure this is indeed needed.

Assessed type

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

Findings Information

🌟 Selected for report: rvierdiiev

Also found by: 0x73696d616f, ladboy233

Labels

bug
2 (Med Risk)
primary issue
satisfactory
selected for report
sponsor acknowledged
edited-by-warden
M-09

Awards

Data not available

External Links

Lines of code

https://github.com/code-423n4/2023-12-initcapital/blob/main/contracts/core/InitCore.sol#L275

Vulnerability details

Proof of Concept

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.

  • Decrease collateral factor for blacklisted wLp until it becomes 0
  • then blacklist wLp

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.

Impact

User can't withdraw previously deposited wLP tokens after they were blacklisted.

Tools Used

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.

Assessed type

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

Findings Information

🌟 Selected for report: ladboy233

Also found by: rvierdiiev

Labels

bug
2 (Med Risk)
disagree with severity
partial-50
sponsor acknowledged
duplicate-9

Awards

Data not available

External Links

Lines of code

https://github.com/code-423n4/2023-12-initcapital/blob/main/contracts/core/InitCore.sol#L288

Vulnerability details

Proof of Concept

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.

Impact

Bad debt is not distributed among all lenders

Tools Used

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.

Assessed type

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:

  1. a liquidator can come in and repay partial debt and take ALL the collaterals (since there are liquidation premiums). So we are left with 0 collateral and >0 debt.
  2. The idea is that we would like to be able to liquidate this debt as well. However, in the liquidate function, it will try to removeCollateral to the liquidator, and there's a check that requires 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.

  1. I agree the main impact is the system insolvency and it's worth keeping this report as Medium because there is no specific solution to resolve.
  2. #9 shows a more severe impact by clarifying that it's impossible to liquidate positions with 0 collaterals. For the above reasons, I think it's appropriate to mark this one as a dup of #9 with 50% partial credit.

#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

Findings Information

🌟 Selected for report: ladboy233

Also found by: rvierdiiev

Labels

bug
2 (Med Risk)
satisfactory
edited-by-warden
duplicate-3

Awards

Data not available

External Links

Lines of code

https://github.com/code-423n4/2023-12-initcapital/blob/main/contracts/core/InitCore.sol#L462

Vulnerability details

Proof of Concept

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.

Impact

It's possible to add more collateral, even when collateralization is paused.

Tools Used

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.

Assessed type

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

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax Β© 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter