# Reentrancy in USDO.flashLoan(), enabling an attacker to borrow unlimited USDO exceeding the max borrow limit

USDO.flashLoan() lacked a reentrancy guard, letting a malicious receiver re-enter via onFlashLoan to borrow unlimited USDO beyond the max borrow limit.

- Payout: Contest reward
- Severity: high
- Program: Tapioca DAO
- Credited: zzzitron
- Disclosed: 2023-11-16
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2023-07-tapioca-findings/issues/1043
- Library page: https://bugbountylibrary.com/r/c4%3A2023-07-tapioca%3AH-32
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:source-review vuln:business-logic vuln:flash-loan vuln:reentrancy

**Target:** USDO.flashLoan() on-chain contract
**Root cause:** USDO.flashLoan() has no reentrancy protection modifier, so the receiver's onFlashLoan callback can re-enter flashLoan before state/limit checks settle.
**Steps:**
1. Deploy a malicious contract implementing the flash-loan receiver interface with an onFlashLoan callback.
2. Call `USDO.flashLoan(receiver, amount, ...)` with the malicious contract as receiver.
3. Inside `onFlashLoan`, re-enter `USDO.flashLoan()` recursively to borrow additional USDO beyond the max borrow limit.
4. Repay/exit and retain the excess borrowed USDO.
**How found:** Code review of USDO.flashLoan() noticing the missing reentrancy modifier and the external onFlashLoan callback as a re-entry point.
**Exploitation:** Attacker contract acts as receiver; the onFlashLoan callback (line 94 USDO.sol) re-enters flashLoan to stack borrows exceeding the max limit, extracting unlimited USDO.
**Insight:** Flash-loan entrypoints that invoke an external receiver callback must be nonReentrant; check whether borrow-limit accounting is updated before or after the callback.
