Skip to content

Latest commit

 

History

History
78 lines (56 loc) · 2.53 KB

File metadata and controls

78 lines (56 loc) · 2.53 KB

Salty Amethyst Caribou

High

Bids canceled or accepted are re-acceptable

Summary

Once Bids are accepted, the state is changed from PENDING to others. Moreover if the borrower canceled the bid, the state is changed to CANCELED. But despite of this, these types of bids are re-acceptable.

Root Cause

In TellerV2.sol::lenderAcceptBid#L500, it checks to see if a pending loan has expired.

function lenderAcceptBid(uint256 _bidId)
    external
    override
    pendingBid(_bidId, "lab")
    whenProtocolNotPaused
    returns (
        uint256 amountToProtocol,
        uint256 amountToMarketplace,
        uint256 amountToBorrower
    )
{
    ...
@>  require(!isLoanExpired(_bidId), "BE");
    ...
}

However, in isLoanExpired() function, it returns false if the bid.state is not equal to BidState.PENDING and if bidExpirationTime[_bidId] is equal to 0.TellerV2.sol::isLoanExpired#L1176-L1184

    function isLoanExpired(uint256 _bidId) public view returns (bool) {
        Bid storage bid = bids[_bidId];

@>      if (bid.state != BidState.PENDING) return false;
@>      if (bidExpirationTime[_bidId] == 0) return false;

        return (uint32(block.timestamp) >
            bid.loanDetails.timestamp + bidExpirationTime[_bidId]);
    }

Following this function, if the state of Bids aren't PENDING,for example Bids were already canceled by borrower or already accepted once, it returns false and the require in lenderAcceptBid()#L500 is passed. The case of bidExpirationTime[_bidId] == 0 is also passed.

Internal pre-conditions

No response

External pre-conditions

No response

Attack Path

No response

Impact

If the accepted bids are accepted again, previous lenders lost their assets and borrowers also lost their totalRepaid assets.

PoC

No response

Mitigation

Fix isLoanExpired() function by following:

    function isLoanExpired(uint256 _bidId) public view returns (bool) {
        Bid storage bid = bids[_bidId];

@>      if (bid.state != BidState.PENDING) return true;
@>      if (bidExpirationTime[_bidId] == 0) return true;

        return (uint32(block.timestamp) >
            bid.loanDetails.timestamp + bidExpirationTime[_bidId]);
    }