Users could manipulate auction outcomes on how bid pricing is determined. This is critical for fair collateral valuation. The key mechanism is the AuctionHouse.getBidDetail() function:
function getBidDetail(
bytes32 loanId
) public view returns (uint256 collateralReceived, uint256 creditAsked) {
// check the auction for this loan exists
uint256 _startTime = auctions[loanId].startTime;
require(_startTime != 0, "AuctionHouse: invalid auction");
// check the auction for this loan isn't ended
require(auctions[loanId].endTime == 0, "AuctionHouse: auction ended");
// assertion should never fail because when an auction is created,
// block.timestamp is recorded as the auction start time, and we check in previous
// lines that start time != 0, so the auction has started.
assert(block.timestamp >= _startTime);
// first phase of the auction, where more and more collateral is offered
if (block.timestamp < _startTime + midPoint) {
// ask for the full debt
creditAsked = auctions[loanId].callDebt;
// compute amount of collateral received
uint256 elapsed = block.timestamp - _startTime; // [0, midPoint[
uint256 _collateralAmount = auctions[loanId].collateralAmount; // SLOAD
collateralReceived = (_collateralAmount * elapsed) / midPoint;
}
// second phase of the auction, where less and less CREDIT is asked
else if (block.timestamp < _startTime + auctionDuration) {
// receive the full collateral
collateralReceived = auctions[loanId].collateralAmount;
// compute amount of CREDIT to ask
uint256 PHASE_2_DURATION = auctionDuration - midPoint;
uint256 elapsed = block.timestamp - _startTime - midPoint; // [0, PHASE_2_DURATION[
uint256 _callDebt = auctions[loanId].callDebt; // SLOAD
creditAsked = _callDebt - (_callDebt * elapsed) / PHASE_2_DURATION;
}
// second phase fully elapsed, anyone can receive the full collateral and give 0 CREDIT
// in practice, somebody should have taken the arb before we reach this condition.
else {
// receive the full collateral
collateralReceived = auctions[loanId].collateralAmount;
//creditAsked = 0; // implicit
}
// Compute collateral and CREDIT bid amounts
// Based on configured auction parameters
// And current block timestamp
}
It calculates bid pricing based on.
Configured auction duration and midpoint
Originating loan collateral deposited
Loan CREDIT debt outstanding
Over the duration, it progressively increases the collateral offered while decreasing the CREDIT asked.
However, there are no validity checks that the inputs passed match the real loan state.
Attackers could manipulate values to artificially trigger more favorable pricing.
Impact
If attackers can influence pricing functions, they could unfairly extract more collateral value while paying less outstanding debt.
Proof of Concept
No formal verification that getBidDetail() pricing parameters match the actual monitored lending market state. This enables faulty oracles to trigger improper pricing and valuation.
Scenario
Eve borrows 10 ETH posting 10 ETH collateral
Eve defaults on loan, entering auction with 10 ETH collateral and 20 ETH debt
When auction bid pricing calculated, Eve manipulates values:
Collateral passed as 20 ETH instead of real 10 ETH
Debt passed as 10 ETH instead of real 20 ETH
Auction ends early with Eve able to claim 20 ETH collateral while only repaying 10 ETH
Lines of code
https://github.com/code-423n4/2023-12-ethereumcreditguild/blob/2376d9af792584e3d15ec9c32578daa33bb56b43/src/loan/AuctionHouse.sol#L118-L161 https://github.com/code-423n4/2023-12-ethereumcreditguild/blob/2376d9af792584e3d15ec9c32578daa33bb56b43/src/loan/LendingTerm.sol#L678-L680 https://github.com/code-423n4/2023-12-ethereumcreditguild/blob/2376d9af792584e3d15ec9c32578daa33bb56b43/src/loan/AuctionHouse.sol#L166-L196
Vulnerability details
Users could manipulate auction outcomes on how bid pricing is determined. This is critical for fair collateral valuation. The key mechanism is the
AuctionHouse.getBidDetail()
function:It calculates bid pricing based on.
Configured auction duration and midpoint
Originating loan collateral deposited
Loan CREDIT debt outstanding
Over the duration, it progressively increases the collateral offered while decreasing the CREDIT asked.
However, there are no validity checks that the inputs passed match the real loan state.
Attackers could manipulate values to artificially trigger more favorable pricing.
Impact
If attackers can influence pricing functions, they could unfairly extract more collateral value while paying less outstanding debt.
Proof of Concept
No formal verification that
getBidDetail()
pricing parameters match the actual monitored lending market state. This enables faulty oracles to trigger improper pricing and valuation.Scenario
Eve borrows 10 ETH posting 10 ETH collateral
Eve defaults on loan, entering auction with 10 ETH collateral and 20 ETH debt
When auction bid pricing calculated, Eve manipulates values:
Collateral passed as 20 ETH instead of real 10 ETH
Debt passed as 10 ETH instead of real 20 ETH
Auction ends early with Eve able to claim 20 ETH collateral while only repaying 10 ETH
Code Flow
Eve borrows 10 ETH loan with 10 ETH collateral
LendingTerm.call()
: Eve defaults on 20 ETH loan debtAuctionHouse.getBidDetail()
: Eve passes manipulated 20 ETH collateral, 10 ETH debt valuesAuctionHouse.bid()
: Eve claims 20 ETH by paying 10 ETH (based on bogus inputs)By manipulating input values to the
getBidDetail()
pricing function, Eve unfairly extracts additional collateral for less debt repayment.Recommended Mitigation Steps
Formally verify
getBidDetail()
inputs vs on-chain statesIntroduce redundancy checking inputs against lending market instances
Cease auctions if mismatches detected
Robust input validation is key to preventing manipulated outcomes.
Assessed type
Oracle