Skip to content

Latest commit

 

History

History
91 lines (65 loc) · 3.09 KB

055.md

File metadata and controls

91 lines (65 loc) · 3.09 KB

Huge Tiger Pike

High

A lender may forfeit their right to claim collateral on a defaulted loan.

Summary

The absence of a check on the returned boolean value from claimCollateralAsNFTLender() can lead to a successful claim without the lender receiving any assets or retaining ownership of the accepted lend offer. This vulnerability specifically arises in scenarios involving defaulted loans with multiple accepted lend offers, particularly when an auction has not been initialized.

Root Cause

In DebitaV3Loan:361, there is a missing check on the returned bool value from claimCollateralAsNFTLender()

Internal pre-conditions

No response

External pre-conditions

No response

Vulnerability Path

  1. a loan with more than 1 acceptedOffers needs to default
  2. a lender must invoke claimCollateralAsLender() before auction is initiated

Impact

The lender is unable to access any proceeds from a future auction. The proceeds would be permanently locked in the loan contract.

PoC

Added to test/fork/Loan/ratio/TwoLenderLoanReceipt.t.sol

function testLenderLosingOwnership() public {
    MatchOffers();
    vm.warp(block.timestamp + 8640010); // loan defaults

    // Verify first lender's ownership
    uint lenderId = DebitaV3LoanContract.getLoanData()._acceptedOffers[0].lenderID;
    assertEq(firstLender, ownershipsContract.ownerOf(lenderId));

    // Check that no NFT or ERC20 is received from claiming
    address prevReceiptOwner = receiptContract.ownerOf(receiptID);
    uint256 prevBalance = AEROContract.balanceOf(firstLender);
    DebitaV3LoanContract.claimCollateralAsLender(0);
    assertEq(prevReceiptOwner, receiptContract.ownerOf(receiptID));
    assertEq(prevBalance, AEROContract.balanceOf(firstLender));

    // Ownership NFT was burned, expect reverts
    vm.expectRevert();
    ownershipsContract.ownerOf(lenderId);
    vm.expectRevert();
    DebitaV3LoanContract.claimCollateralAsLender(0);
    vm.expectRevert();
    DebitaV3LoanContract.createAuctionForCollateral(0);

    // Second lender starts auction
    vm.startPrank(secondLender);
    DebitaV3LoanContract.createAuctionForCollateral(1);
    
    // Buyer purchases collateral NFT from auction
    vm.startPrank(buyer);
    deal(AERO, buyer, 1000e18);
    AEROContract.approve(address(auction), 100e18);
    auction.buyNFT();
    vm.stopPrank();

    // First lender cannot claim any proceedings
    vm.expectRevert();
    DebitaV3LoanContract.claimCollateralAsLender(0);

    // Second lender receives their portion
    uint256 prevBalanceSecondLender = AEROContract.balanceOf(secondLender);
    vm.startPrank(secondLender);
    DebitaV3LoanContract.claimCollateralAsLender(1);
    assertTrue(prevBalanceSecondLender < AEROContract.balanceOf(secondLender));
    vm.stopPrank();
}

Mitigation

         if (m_loan.isCollateralNFT) {
-           claimCollateralAsNFTLender(index);
+           require(claimCollateralAsNFTLender(index), "claim not successful");
         } else {