# CNote updates the accounts after sending the funds, allowing for reentrancy

CNote.borrowFresh transfers funds before updating borrow accounting, letting a reentrant token call exitMarket to erase debt and drain funds.

- Payout: Audit contest
- Severity: medium
- Program: Canto
- Found by: hyh
- Disclosed: 2022-10-18
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2022-06-newblockchain-findings/issues/311
- Library page: https://bugbountylibrary.com/r/c4%3A2022-06-canto%3AM-07
- Tags: area:web3 domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:chained technique:source-review vuln:reentrancy

**Target:** CNote lending market contract (borrowFresh/doTransferOut)
**Root cause:** borrowFresh calls doTransferOut before writing accountBorrows/totalBorrows, and neither CNote nor Comptroller.exitMarket has reentrancy protection, so a malicious underlying token can reenter during transfer.
**Steps:**
1. Attacker borrows via CNote.borrow() -> borrowInternal() -> borrowFresh()
2. borrowFresh calls doTransferOut(borrower, borrowAmount) before updating accountBorrows
3. Underlying token's transfer callback reenters Comptroller.exitMarket(cTokenAddress)
4. exitMarket removes the account's debt from liquidity calculation since storage not yet updated
5. Attacker retains borrowed funds with debt erased, repeat to drain cash
**How found:** Code review of borrowFresh ordering: noticed doTransferOut precedes storage writes, contrasted with CToken.borrowFresh which writes borrow state before transfer, and identified exitMarket as an unprotected reentry path.
**Exploitation:** Requires an underlying token with transfer hooks (e.g. ERC777-style callback). During doTransferOut the attacker reenters exitMarket to clear the borrow record, then keeps the transferred funds; repeated borrowing drains available liquidity.
**Insight:** When auditing Compound forks, diff borrowFresh against upstream CToken: any fork that moves doTransferOut before the accountBorrows/totalBorrows writes reintroduces the classic reentrancy, exploitable via exitMarket or any unprotected state-mutating entrypoint reachable from the token transfer callback.

