#47118 [SC-High] Incorrect Allowance Validation in addCollateralBeforeSettle

Submitted on Jun 9th 2025 at 03:23:03 UTC by @Catchme for IOP | Term Structure Institutional

  • Report ID: #47118

  • Report Type: Smart Contract

  • Report severity: High

  • Target: https://github.com/term-structure/tsi-contract/blob/main/src/Settlement.sol

  • Impacts:

    • Protocol insolvency

    • Griefing (e.g. no profit motive for an attacker, but damage to the users or the protocol)

Description

Brief/Intro

The addCollateralBeforeSettle function in Settlement.sol contains a critical logic flaw in its allowance validation mechanism. The function incorrectly validates the caller's (msg.sender) token allowance instead of validating the actual fund provider's (taker's) allowance. This disconnect between validation and execution allows any user to artificially inflate collateral requirements without ensuring proper financial backing.

Vulnerability Details

The issue is located at lines 189-190 in Settlement.sol:

function addCollateralBeforeSettle(string memory _loanId, uint256 addedAmount) public nonReentrant {
    bytes32 loanId = _loanId.toBytes32();
    
    LoanInfo memory loanInfo = loans[loanId];
    if (loanInfo.maker == address(0)) {
        revert LoanNotFound(loanId);
    }
    if (loanInfo.settled) {
        revert LoanAlreadySettled(loanId);
    }
    loanInfo.addCollateral(addedAmount);
    if (settlements[loanInfo.settlementId].takerType == TakerType.BORROW) {
        // BUG: Validates wrong address allowance
        uint256 allowance = IERC20(loanInfo.collateralTokenAddr).allowance(msg.sender, address(this));
        if (allowance < loanInfo.debtData.collateralAmt) {
            revert TokenAllowanceInsufficient(allowance, loanInfo.debtData.collateralAmt);
        }
    }
    
    loans[loanId] = loanInfo;
    emit CollateralAdded(msg.sender, loanId, addedAmount);
}

The root cause of this vulnerability is that:

  1. In the settlement flow, collateral tokens flow from the borrower (taker) to the lender

  2. However, the function validates msg.sender's allowance, who may be neither party

  3. This creates a disconnect between authorization verification and actual fund transfer logic

  4. During settlement, the actual borrower's allowance may be insufficient, causing transaction failures

The logical flaw: When takerType is BORROW, the collateral should come from the borrower (taker), but the function validates an arbitrary caller's allowance instead.

Impact Details

  1. Financial Risk:

    • Users can manipulate loan collateral records without corresponding financial backing

    • Creates phantom collateral that cannot be honored during settlement

    • Potential for economic losses when transactions fail in volatile markets

  2. System Stability:

    • Settlement operations will fail when collateral transfer attempts exceed the taker's actual allowance

    • Core lending functionality breaks down, compromising the protocol's reliability

    • Transaction failures during critical market movements could cause significant financial losses

Proof of Concept

Proof of Concept

Was this helpful?