Lavarage Arbitrary Router Drain
Exploit Transactions
0xba473228bd61e8ba4bd8c8c9f411d863a24091fb301d6f25c63b693a2d325bf60x6598c2c962e5a019abedb40f1480c3e7bf0e09a8aaa7bdc549c36239dd7ee4060xc291d70f281dbb6976820fbc4dbb3cfcf56be7bf360f2e823f339af4161f64c6Victim Addresses
0x2eed3dc9c5134c056825b12388ee9be04e522173BSC0x616b36265759517af14300ba1dd20762241a3828BSCLoss Breakdown
Similar Incidents
Transit Router V5 Drain
38%SellToken Arbitrary-Pair LP Drain
37%MultiSender Arbitrary From Theft
34%KEKESANTA Pair-to-Router Double-Credit Liquidity Drain
34%GymRouter Arbitrary Approved Token Spend
34%SwapX Arbitrary transferFrom Approval Drain on BNB Chain
34%Root Cause Analysis
Lavarage Arbitrary Router Drain
1. Incident Overview TL;DR
On BSC block 63856735, attacker EOA 0x3fee6d8aaea76d06cf1ebeaf6b186af215f14088 used freshly deployed helper contract 0xe82fc275b0e3573115eadca465f85c4f96a6c631 to call Lavarage BorrowerOperations proxy 0x616b36265759517af14300ba1dd20762241a3828. That flow redirected protocol privilege into TokenHolder proxy 0x2eed3dc9c5134c056825b12388ee9be04e522173, which transferred out 20 WBNB. The transaction ended with 19.2 WBNB on the attacker helper and 0.8 WBNB on fee recipient 0x8432CD30C4d72Ee793399E274C482223DCA2bF9e.
The root cause is an access-control failure in BorrowerOperationsV6.sell: the incident implementation trusted attacker-supplied tokenHolder, inchRouter, whitelistedDex, and calldata instead of binding the sell flow to a legitimate protocol loan and approved router. That let any unprivileged attacker supply a fake loan source and then make BorrowerOperations perform a real privileged call against TokenHolder.
2. Key Background
Lavarage’s TokenHolder is a reserve-holding contract, not a public flash-loan pool. Its privilegedLoan(IERC20,uint256) function can move reserve tokens only for callers with BORROWER_ROUTER_ROLE. At incident time, BorrowerOperations proxy 0x616b36265759517af14300ba1dd20762241a3828 held that role on TokenHolder proxy 0x2eed3dc9c5134c056825b12388ee9be04e522173.
That privilege relationship matters because BorrowerOperations.sell is supposed to operate only on authentic protocol loan records. Once the function trusts attacker-controlled loan metadata and attacker-chosen router calldata, BorrowerOperations becomes a confused deputy: it still has the protocol’s role on TokenHolder, but it no longer ensures the underlying sell action belongs to a real protocol loan.
The collected trace confirms the exact runtime relationship:
0x616B36265759517AF14300Ba1dD20762241a3828::sell(...)
0x8c7f34436C0037742AeCf047e06fD4B27Ad01117::sell(...) [delegatecall]
0x2EeD3DC9c5134C056825b12388Ee9Be04E522173::privilegedLoan(WBNB, 20000000000000000000)
3. Vulnerability Analysis & Root Cause Summary
The vulnerability class is a direct permissioned-call redirection bug. BorrowerOperationsV6.sell consumed attacker-controlled parameters for the source of loan state, the DEX/router targets, and the arbitrary call payload that would be executed during the sell path. The function therefore lost provenance over both the loan being closed and the privileged external call it was about to trigger.
The violated invariant is straightforward: a sell flow must only operate on a genuine loan record created by the protocol, and any privileged TokenHolder transfer must stay bound to that same authenticated protocol state transition. In the incident implementation, that invariant broke at the point where BorrowerOperationsV6.sell trusted tokenHolder.loans(loanId) from an attacker contract and later executed a low-level call to attacker-selected inchRouter with attacker-selected calldata.
The concrete breakpoint is the privileged path from BorrowerOperationsV6.sell into TokenHolder.privilegedLoan. Once the attacker made BorrowerOperations believe a fake loan existed, the protocol’s own router privilege on the real TokenHolder was enough to move reserve WBNB out of the victim contract.
4. Detailed Root Cause Analysis
The exploit sequence begins with attacker helper 0xe82fc275b0e3573115eadca465f85c4f96a6c631. The helper exposes functions that satisfy the interface BorrowerOperations.sell expects from a TokenHolder, but those functions return attacker-chosen values. In the trace, BorrowerOperations first reads fake loan state from the helper:
0xe82F...c631::loans(0) [staticcall]
← collateralAddress = WBNB
← collateralAmount = 0
← borrower = 0xe82F...c631
← userPaid = 0
Because BorrowerOperationsV6.sell trusted that return data, it proceeded as if it were unwinding a legitimate protocol position. The function then made a privileged internal-style call back into the attacker helper:
0xe82F...c631::privilegedLoan(WBNB, 0)
That helper implementation was a no-op, so the flow continued without resistance. The decisive step came next, when the attacker-supplied inchRouter argument pointed to the real TokenHolder proxy and the attacker-supplied calldata encoded privilegedLoan(WBNB, 20 ether). The trace shows the protocol performing that exact call:
0x2EeD3DC9c5134C056825b12388Ee9Be04E522173::privilegedLoan(
WBNB,
20000000000000000000
)
WBNB::transfer(
0x616B36265759517AF14300Ba1dD20762241a3828,
20000000000000000000
)
At that point, the real TokenHolder reserve lost 20 WBNB and transferred it into the BorrowerOperations flow because BorrowerOperations still held BORROWER_ROUTER_ROLE. There was no genuine debt to repay because the loan record was fabricated. The subsequent payout logic therefore treated the stolen WBNB as proceeds and distributed it according to the protocol’s normal fee logic:
WBNB::transfer(0x8432CD30C4d72Ee793399E274C482223DCA2bF9e, 800000000000000000)
WBNB::transfer(0xe82F...c631, 800000000000000000)
WBNB::transfer(0xe82F...c631, 18400000000000000000)
The end state is deterministic. The victim TokenHolder lost exactly 20 WBNB; the fee recipient gained 0.8 WBNB; and the attacker helper gained 19.2 WBNB. The balance-diff artifact also shows the originating EOA paid 17988800000000 wei in gas, which is immaterial to the exploit’s profitability.
5. Adversary Flow Analysis
The adversary flow has three on-chain stages:
- Transaction
0xba473228bd61e8ba4bd8c8c9f411d863a24091fb301d6f25c63b693a2d325bf6deployed helper contract0xe82fc275b0e3573115eadca465f85c4f96a6c631. - Transaction
0x6598c2c962e5a019abedb40f1480c3e7bf0e09a8aaa7bdc549c36239dd7ee406configured that helper before the drain. - Transaction
0xc291d70f281dbb6976820fbc4dbb3cfcf56be7bf360f2e823f339af4161f64c6executed the drain by calling the helper, which in turn calledBorrowerOperations.sell.
The runtime call chain in the exploit transaction is evidence-backed and complete:
EOA 0x3fee...4088
-> helper 0xe82F...c631
-> BorrowerOperations proxy 0x616B...3828
-> BorrowerOperationsV6 implementation 0x8c7f...1117 [delegatecall]
-> helper::loans(0)
-> TokenHolder proxy 0x2EeD...2173::privilegedLoan(WBNB, 20 ether)
-> WBNB transfers to fee recipient and attacker helper
This is an ACT exploit because no privileged attacker-side access was required. Any unprivileged EOA could deploy the helper contract, call the public protocol entrypoint, and reuse the existing BORROWER_ROUTER_ROLE relationship that the protocol itself had granted to BorrowerOperations.
6. Impact & Losses
The measurable victim loss in the incident transaction was 20 WBNB from TokenHolder proxy 0x2eed3dc9c5134c056825b12388ee9be04e522173. Of that amount, 19.2 WBNB accrued to the attacker helper as direct profit and 0.8 WBNB accrued to the protocol fee recipient as part of the same exploit path.
The affected party was the Lavarage reserve-holding TokenHolder contract. The exploit did not rely on repeated looping or complex market conditions; a single transaction was sufficient to redirect privileged TokenHolder liquidity into the attacker’s control.
7. References
- Seed exploit transaction:
0xc291d70f281dbb6976820fbc4dbb3cfcf56be7bf360f2e823f339af4161f64c6 - Attacker deployment transaction:
0xba473228bd61e8ba4bd8c8c9f411d863a24091fb301d6f25c63b693a2d325bf6 - Attacker preparation transaction:
0x6598c2c962e5a019abedb40f1480c3e7bf0e09a8aaa7bdc549c36239dd7ee406 - BorrowerOperations proxy:
0x616b36265759517af14300ba1dd20762241a3828 - BorrowerOperations implementation:
0x8c7f34436c0037742aecf047e06fd4b27ad01117 - TokenHolder proxy:
0x2eed3dc9c5134c056825b12388ee9be04e522173 - TokenHolder implementation:
0x3403f2ba8aa448c208c2d1a41f2089c5a6f924e4 - WBNB token:
0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c - Fee recipient:
0x8432CD30C4d72Ee793399E274C482223DCA2bF9e - Primary evidence artifacts: seed transaction metadata, seed opcode trace, and seed balance-diff artifacts collected under the session collector outputs