An attacker can steal any loan opening for auction for free by executing the Lender::buyLoan()
and inputting anyone else's poolId
as an argument.
Root cause: the buyLoan()
lacks verification that a caller (msg.sender
) must be the new pool's lender.
Therefore, an attacker (which can be anyone, including a current pool's lender) can execute the buyLoan()
to force anyone else's lending pool to pay the loan's total debt for the attacker.
Subsequently, the forced pool has to pay for the debt but the attacker will become a new lender for free.
The forced pool has to pay for the debt
: https://github.com/Cyfrin/2023-07-beedle/blob/658e046bda8b010a5b82d2d85e824f3823602d27/src/Lender.sol#L489
The attacker will become a new lender
: https://github.com/Cyfrin/2023-07-beedle/blob/658e046bda8b010a5b82d2d85e824f3823602d27/src/Lender.sol#L518
Once a borrower repays the loan, the attacker address will be used to compute the poolId
. The computed poolId
will point to the attacker's pool. This way, the attacker can steal the loan principal (loan.debt
) and interest (lenderInterest
).
The attacker address will be used to compute the poolId
: https://github.com/Cyfrin/2023-07-beedle/blob/658e046bda8b010a5b82d2d85e824f3823602d27/src/Lender.sol#L304
The computed poolId will point to the attacker's pool
: https://github.com/Cyfrin/2023-07-beedle/blob/658e046bda8b010a5b82d2d85e824f3823602d27/src/Lender.sol#L311-L312
An attacker can steal any loan opening for auction for free by executing the buyLoan()
and inputting anyone else's poolId
as an argument. This vulnerability is considered a high-risk issue.
Manual Review
I recommend verifying that a caller (msg.sender
) of the buyLoan()
must be the new pool's lender, as shown below.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.