# Juicebox REVLoans: fake loan source inflates borrow to drain treasury

REVLoans trusted a caller-supplied loan source terminal, letting an attacker register a fake 36-decimal source to inflate totalBorrowedFrom and borrow real ETH against tiny collateral.

- Payout: Real-world hack
- Severity: critical
- Program: JuiceboxREVLoans
- Credited: DefimonAlerts
- Disclosed: 2026-04-20
- Write-up quality: 8/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2026-04/JuiceboxREVLoans_exp.sol
- Library page: https://bugbountylibrary.com/r/dhl%3A20260420-juiceboxrevloans
- Tags: domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:critical tech:evm tech:solidity technique:chained technique:source-review vuln:accounting-error vuln:business-logic vuln:oracle-manipulation

**Target:** REVLoans borrowFrom loan source validation / JBMultiTerminal treasury
**Root cause:** REVLoans registers any caller-supplied (token, terminal) pair as a loan source on first borrowFrom() and trusts that source's accountingContextForTokenOf decimals, so a fake source reporting 36 decimals inflates the recorded borrowed amount without real assets moving.
**Steps:**
1. Attacker calls `JBMultiTerminal.pay{value: 0.0001 ether}(3, NATIVE_TOKEN, ...)` to obtain revnet #3 tokens for collateral.
2. Attacker calls `JBPermissions.setPermissionsFor(ATTACKER, {operator: REV_LOANS, projectId: 3, permissionIds: [10]})` to allow burning tokens as collateral.
3. Attacker deploys FakeLoanSourceTerminal returning `decimals()=36` and `accountingContextForTokenOf(...)= {decimals:36, currency:61166}`.
4. Attacker calls `REVLoans.borrowFrom(3, {token: fakeSource, terminal: fakeSource}, 0, 22903320800000000, ATTACKER, 25)` registering the fake source and inflating totalBorrowedFrom.
5. Attacker calls `REVLoans.borrowFrom(3, {token: NATIVE_TOKEN, terminal: JB_MULTI_TERMINAL}, 0, 65301882816341, ATTACKER, 25)` to borrow real ETH against the inflated borrowed total.
6. Attacker receives ~21.77 ETH profit.
**How found:** Likely code review of REVLoans.borrowFrom showing the loan source (token, terminal) is caller-supplied and registered on first use, combined with noticing the source's decimals feed into the borrowed-total accounting, enabling a fake high-decimals source to inflate totals.
**Exploitation:** Attacker seeds a tiny amount of revnet #3 tokens, grants REVLoans burn permission, then opens a loan against a self-deployed fake terminal/token that reports 36 decimals. REVLoans records a huge totalBorrowedFrom for the fake source. The attacker then borrows native ETH from the real JBMultiTerminal with minimal real collateral, since the inflated fake-source total satisfies the loan accounting, draining treasury ETH to the attacker.
**Insight:** When a lending/borrowing contract accepts a caller-supplied (token, terminal) pair and lazily registers it as trusted, deploy a fake source whose decimals()/accountingContextForTokenOf returns an absurd value (e.g. 36) to inflate recorded borrow totals and unlock real-asset borrowing against negligible collateral.
