The Wildcat Protocol - josephdara's results

Banking, but worse - a protocol for fixed-rate, undercollateralised credit facilities.

General Information

Platform: Code4rena

Start Date: 16/10/2023

Pot Size: $60,500 USDC

Total HM: 16

Participants: 131

Period: 10 days

Judge: 0xTheC0der

Total Solo HM: 3

Id: 296

League: ETH

Wildcat Protocol

Findings Distribution

Researcher Performance

Rank: 9/131

Findings: 3

Award: $664.37

🌟 Selected for report: 0

🚀 Solo Findings: 0

Lines of code

https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/market/WildcatMarket.sol#L142-L149

Vulnerability details

Impact

The function closeMarket() sets the APR to 0% and does the necessary fund transfers. This function implements a modifier onlyController, this requires that only the controller can make this call. However the controller contract has no method that calls the function closeMarket().

Proof of Concept

  modifier onlyController() {
    if (msg.sender != controller) revert NotController();
    _;
  }

 function closeMarket() external onlyController nonReentrant {}

In the Market Controller contract available at https://github.com/code-423n4/2023-10-wildcat/blob/main/src/WildcatMarketController.sol, there exists no function to call the closeMarket()

Tools Used

Manual Review

Add a function in the Market Controller contract that calls WildcatMarket.closeMarket()

Assessed type

Other

#0 - c4-pre-sort

2023-10-27T07:08:22Z

minhquanym marked the issue as duplicate of #147

#1 - c4-judge

2023-11-07T13:53:20Z

MarioPoneder changed the severity to 2 (Med Risk)

#2 - c4-judge

2023-11-07T14:01:07Z

MarioPoneder marked the issue as partial-50

#3 - c4-judge

2023-11-07T14:16:53Z

MarioPoneder changed the severity to 3 (High Risk)

Findings Information

🌟 Selected for report: MiloTruck

Also found by: josephdara

Labels

bug
2 (Med Risk)
partial-50
duplicate-498

Awards

647.6492 USDC - $647.65

External Links

Lines of code

https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/WildcatSanctionsSentinel.sol#L100-L102 https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/market/WildcatMarketWithdrawals.sol#L164-L170

Vulnerability details

Impact

Markets can be added and removed from the ArchController by the controller and owner respectively. Removal of a market from the ArchController is expected, however this creates an issue for sanctioned acccount.

Proof of Concept

Sanctioned accounts are unable to make a withdrawal because the function createEscrow checks if the market is registered.

  function createEscrow(
    address borrower,
    address account,
    address asset
  ) public override returns (address escrowContract) {
     if (!IWildcatArchController(archController).isRegisteredMarket(msg.sender)) {
      revert NotRegisteredMarket();
    }

This causes a DOS for addresses with a sanction as the transaction would always revert and users will not get their funds. After a discussion with the sponsor, it was said that the check will be removed from the sanctions sentinel to keep it from affecting withdrawal.

Tools Used

Manual Review

As said by the sponsor, the check would be removed to allow santioned users access their funds.

Assessed type

Error

#0 - c4-pre-sort

2023-10-28T18:04:51Z

minhquanym marked the issue as duplicate of #498

#1 - c4-judge

2023-11-07T12:22:05Z

MarioPoneder marked the issue as not a duplicate

#2 - c4-judge

2023-11-08T17:01:05Z

MarioPoneder marked the issue as unsatisfactory: Insufficient proof

#3 - Josephdara

2023-11-13T19:50:47Z

Hello @MarioPoneder This issue is a duplicate of #498 because the core issue is the same. If a market is removed, sanctioned lenders will be unable to call executeWithdrawal() to withdraw their assets from the market into their own escrows.This is because an escrow account is created for the sanctioned users when they try to withdraw, however withdrawal reverts because of the check I highlighted above.

  function createEscrow(
    address borrower,
    address account,
    address asset
  ) public override returns (address escrowContract) {
     if (!IWildcatArchController(archController).isRegisteredMarket(msg.sender)) {
      revert NotRegisteredMarket();
    }

This causes a DOS for addresses with a sanction as the transaction would always revert and users will not get their funds.

I provided all this in the report above.

#4 - MarioPoneder

2023-11-14T22:09:10Z

Thank you for your comment!

In contrast to the primary issue, the present report has not identified all impacts and is lacking quality (level of detail) as well as proof.
Nevertheless, I acknowledge that the withdrawal DoS was identified and therefore willing to restore duplication with partial credit.

#5 - c4-judge

2023-11-14T22:09:23Z

MarioPoneder marked the issue as duplicate of #498

#6 - c4-judge

2023-11-14T22:09:44Z

MarioPoneder marked the issue as partial-50

Awards

16.6643 USDC - $16.66

Labels

bug
2 (Med Risk)
satisfactory
duplicate-196

External Links

Lines of code

https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/WildcatMarketController.sol#L67-L68 https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/WildcatMarketController.sol#L468-L488 https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/market/WildcatMarketConfig.sol#L149-L159

Vulnerability details

Impact

When markets are deployed using the Factory deployControllerAndMarket() or with the controllerdeployMarket(), a check is performed on the AnnualInterestBips It is ensured that the APR is always less than maximumAnnualInterestBips preset in the factory and greater than the MinimumAnnualInterestBips However, a borrower can increase or reduce the market's APR to any value using the WildcatMarketController.setAnnualInterestBips() It can be set to zero, or any amount greater than the allowed maximum from the Factory contract. After a discussion with the spponsor, this was confirmed to be an issue.

Proof of Concept

The function setAnnualInterestBips() does no checks to ensure the limiters on the new annualInterestBips.

function setAnnualInterestBips(
    address market,
    uint16 annualInterestBips
  ) external virtual onlyBorrower onlyControlledMarket(market) {
    // If borrower is reducing the interest rate, increase the reserve
    // ratio for the next two weeks.
    if (annualInterestBips < WildcatMarket(market).annualInterestBips()) {
      TemporaryReserveRatio storage tmp = temporaryExcessReserveRatio[market];

      if (tmp.expiry == 0) {
        tmp.reserveRatioBips = uint128(WildcatMarket(market).reserveRatioBips());

        // Require 90% liquidity coverage for the next 2 weeks
        WildcatMarket(market).setReserveRatioBips(9000);
      }

      tmp.expiry = uint128(block.timestamp + 2 weeks);
    }

    WildcatMarket(market).setAnnualInterestBips(annualInterestBips);
  }

The sanity check is very important this point because there also is no check inside the market contract except the BIP value.

Tools Used

Manual Review

As discussed with the sponsor, the max and min values can be stored as an immutable in the market contract and checked directly in the WildCatMarket.setAnnualInterestBips() function.

Assessed type

Math

#0 - c4-pre-sort

2023-10-27T14:14:27Z

minhquanym marked the issue as duplicate of #443

#1 - c4-judge

2023-11-07T12:26:02Z

MarioPoneder 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