Calculated from recorded token losses using historical USD prices at the incident time.
0x93a9b022df260f1953420cd3e18789e7d1e095459e36fe2eb534918ed16874920xd55f01b4b51b7f48912cd8ca3cdd8070a1a9dba5BSC0x157822ac5fa0efe98daa4b0a55450f4a182c10caBSC0x4f3e801bd57dc3d641e72f2774280b21d31f64e4BSCRifi Finance on BNB Chain was drained because its live SimplePriceOracle let any caller replace the oracle source for a listed market. In transaction 0x93a9b022df260f1953420cd3e18789e7d1e095459e36fe2eb534918ed1687492 at block 16956475, the adversary minted a dust-sized rBNB position, entered it as collateral, rewired rBNB's oracle entry to an attacker-controlled feed, borrowed the full cash from five Rifi markets, swapped the proceeds into BNB, restored the original oracle entry, and exited with 2571.132785858093388257 BNB of net profit.
Rifi computes borrowing power through its Unitroller/Cointroller liquidity checks. For each entered collateral market, the protocol reads an account snapshot from the rToken and then asks the configured price oracle for the underlying asset price. For rBNB, that price source is stored in SimplePriceOracle.oracleData[address(rToken)]. If that mapping can be changed by an untrusted user, the protocol's collateral valuation becomes attacker-controlled and every downstream borrow check becomes meaningless.
The drained markets in this incident were the RBep20 wrappers for USDC, BTCB, DAI, USDT, and BUSD. The attack did not require governance power, private keys, or any privileged role. It required only a public transaction against a public oracle setter.
The vulnerability is an access-control failure in the oracle-configuration path. Rifi's SimplePriceOracle exposed setOracleData as an unrestricted external function, so any user could replace the feed pointer for a listed market. The same contract's function blindly trusted the current mapping entry and converted the returned Chainlink answer into the price consumed by collateral checks. Because Unitroller/Cointroller relied on that oracle output during , a borrower could mint a tiny collateral position, swap in an attacker-controlled oracle, and manufacture almost arbitrary borrowing power. The attack therefore breaks the core invariant that only trusted governance should control the price source used for collateral valuation. Once that invariant failed, the remaining protocol logic behaved as designed but on false prices.
getUnderlyingPricegetAccountLiquidityThe critical code path is short and direct. The verified oracle source contains the following logic:
mapping(address => oracleChainlink) public oracleData;
function setOracleData(address rToken, oracleChainlink _oracle) external {
oracleData[rToken] = _oracle;
}
function getUnderlyingPrice(RToken rToken) public view returns (uint) {
uint decimals = oracleData[address(rToken)].decimals();
(, int256 answer, , , ) = oracleData[address(rToken)].latestRoundData();
return 10 ** (18 - decimals) * uint(answer);
}
That code gives any external caller write access to oracleData, then immediately trusts the chosen oracle during price reads. In the seed transaction, the attacker first minted 499553304430711102439309 rBNB with only 100000000000000 wei and entered rBNB as collateral. Before any spoofing, the protocol valued that position conservatively and returned only 29137327582548960 of account liquidity.
The trace then shows the exact oracle mutation:
SimplePriceOracle::setOracleData(
RBinance: [0x157822aC5fa0Efe98daa4b0A55450f4a182C10cA],
0xA36F6F78B2170a29359C74cEFcB8751E452116f9
)
storage:
0x0567F2323251f0Aab15c8dFb1967E4e8A7D42aeE
-> 0xA36F6F78B2170a29359C74cEFcB8751E452116f9
Immediately afterward, getAccountLiquidity re-ran using the attacker-supplied feed and the same rBNB balance. The trace records liquidity jumping from 29137327582548960 to 29181680230147386998020193924. That inflated value unlocked the protocol's borrow path for every drained market. The attacker then borrowed the full available cash from rUSDC, rBTCB, rDAI, rUSDT, and rBUSD, sold those assets through PancakeSwap, restored the original rBNB oracle pointer, and transferred the proceeds out.
This is a direct integrity failure in collateral pricing. The exploit does not depend on flash liquidity, stale state, or a second bug in the borrow logic. The sole root cause is that Rifi let untrusted users choose the oracle source that determines borrowing power.
The adversary-controlled EOA was 0x803e0930357ba577dc414b552402f71656c093ab. It sent a single transaction to helper contract 0xe6df12a9f33605f2271d2a2ddc92e509e54e6b5f, which executed the full exploit atomically.
First, the helper minted a dust rBNB position and entered that market as collateral. Second, it called SimplePriceOracle.setOracleData to replace the canonical rBNB feed 0x0567F2323251f0Aab15c8dFb1967E4e8A7D42aeE with attacker-controlled feed 0xA36F6F78B2170a29359C74cEFcB8751E452116f9. Third, after the collateral value was inflated, it borrowed the entire cash balances from the five victim markets. Fourth, it approved PancakeSwap and sold each borrowed asset into BNB. Finally, it restored the original oracle entry and transferred the BNB proceeds back to the EOA.
The balance-diff evidence matches that flow. The attacker EOA increased from 848051840000000000 wei to 2571980837698093388257 wei, for a net delta of 2571132785858093388257 wei after fees. The helper contract ended at zero native balance, which is consistent with its role as a transient execution vehicle.
The exploit drained all available cash from five Rifi borrow markets and left the protocol with bad debt backed by grossly mispriced rBNB collateral. The recorded token losses were:
USDC: 346199780826500224370302BTCB: 3032997772596307847DAI: 52275872910150015513225USDT: 297082798044846109795784BUSD: 299822459019477022693829The realized profit predicate was native BNB. The attacker's measured gain was 2571132785858093388257 wei net of transaction fees.
0x93a9b022df260f1953420cd3e18789e7d1e095459e36fe2eb534918ed1687492 on BNB Chain block 16956475SimplePriceOracle at 0xd55f01b4b51b7f48912cd8ca3cdd8070a1a9dba5rBNB at 0x157822ac5fa0efe98daa4b0a55450f4a182c10caUnitroller/Cointroller at 0x4f3e801bd57dc3d641e72f2774280b21d31f64e4rUSDC 0x916e87d16b2f3e097b9a6375dc7393cf3b5c11f5, rBTCB 0x53abf990bf7a37faa783a75fdd75bbcf8bdf11eb, rDAI 0x9b9006cb01b1f664ac25137d3a3a20b37d8bc078, rUSDT 0x383598668c025be0798e90e7c5485ff18d311063, rBUSD 0x6db6a55e57ac8c90477bbf00ce874b988666553aSimplePriceOracle source, the seed transaction trace excerpt, the full seed trace, and the seed balance-diff artifact