Rubicon — disclosed vulnerability reports and payouts
Every publicly disclosed and closed bug bounty report we hold for Rubicon, with our own summary of each finding and a link to the original disclosure.
- Reports indexed
- 42
- Total paid
- $0
- Critical
- 0
- Largest payout
- $0
This page collects the 42 closed, publicly disclosed Rubicon reports indexed on CoinBuggie. Nothing here is active or unpatched — every entry was published by the programme or the researcher after remediation.
The findings concentrate in Logic error, Front-running / MEV, Integer overflow / underflow, Reentrancy, Oracle manipulation, across EVM-Solidity. Reading a single protocol end to end is the fastest way to see which assumptions its codebase repeatedly gets wrong, which is usually a better predictor of where the next finding lives than the category alone.
Use the vulnerability class links below to compare these findings against the same bug class in other protocols.
What reviewers look for
- Logic error findings disclosed against Rubicon
- Front-running / MEV findings disclosed against Rubicon
- Integer overflow / underflow findings disclosed against Rubicon
- Reentrancy findings disclosed against Rubicon
- Oracle manipulation findings disclosed against Rubicon
Curated highlights
The largest disclosed payouts in this group, with our own summary of each. Every report links back to the original disclosure.
Rubicon: Rewards for initial period may be lost in `BathBuddy` contract
Rubicon's BathBuddy rewards contract starts accruing rewards the moment the owner calls notifyRewardAmount, which computes a per-second reward rate and sets the cycle's lastUpdateTime and periodFinish regardless of whether any BathTokens are circulating. Because the reward clock runs before any holder exists, the rewards emitted during that zero-supply prefix can never be attributed to anyone and remain permanently stranded in the contract. A verbatim Foundry PoC shows a participant joining at the midpoint of a 10,000-second cycle receiving only half the rewarded tokens while the other half stays locked in the BathBuddy contract. The economic impact is most significant when bootstrapping a newly created Bath pair, where the cycle starts before any holders exist.
Rubicon: Wrong calculation of repayment amount in Position contract
Rubicon's Position wrapper computes a user's repayment obligation in borrowBalanceOfPos by taking the current borrowRatePerBlock and multiplying it by the number of blocks since the position was opened. Because borrowRatePerBlock is a function of the pool's live borrows and supply, the rate almost never stays constant over the lifetime of the loan, so this single-rate approximation over- or under-states the true accrued interest. In practice, when other users open leveraged positions after a borrower, the borrower is charged interest at the inflated current rate on close, causing more asset than necessary to be swapped to quote in the repayment path.
Rubicon: When opening a position, the collateral of the previous position is used for borrowing, which makes the user more easily liquidated
Rubicon's Position.buyAllAmountWithLeverage lets the borrow loop for a new position include the leftover borrowable capacity (via _maxBorrow) of collateral already locked in a user's prior levered positions. Because that previously minted debt is counted again, a user who opens successive leveraged longs gets debt against collateral that never received fresh backing, silently pushing them toward the liquidation threshold. The reporter demonstrates that opening a 1.6x then a 1.8x WBTC long back-to-back drives the account's comptroller liquidity from [0, 9e16, 0] to [0, 0, 0], so any small price drop triggers liquidation. The maintainer acknowledged the over-borrowing as intended behavior, but the judge upheld the finding as High given the very high liquidation probability it creates.
Rubicon: `Position` contract allows to interact with positions that are liquidated
Rubicon's Position helper lets a borrower add collateral to a lending position even after that position's collateral has already been liquidated. Because the position records its collateral quantity at creation and closePosition must redeem exactly that amount from the Position contract's own bathToken balance, a margin increase requested just after liquidation mints new bathTokens that can never be withdrawn — the redeem amount permanently exceeds what the contract holds. The confirmed result is that the additional collateral is locked forever, usable only as borrowing collateral, representing a direct loss for the user.
Rubicon: DOS of market operations with malicious offers
Rubicon's orderbook fills trades by repeatedly pulling the best-priced offer from a price-sorted linked list inside buyAllAmount/sellAllAmount, but the offer() entry point never validates the owner or recipient addresses. A malicious maker can post a small, aggressively-priced order whose payout lands at the zero address; because standard OpenZeppelin ERC20s revert on zero-address transfers, that head offer becomes permanently unfillable and reverts the entire fill loop, DoSing every trade on the pair. The same poison blocks Position.sol, which can only fill via those two functions and cannot pick offers by id, so users are left unable to unwind before liquidation, and new matched-order creation in _matcho is also blocked. The protocol confirmed the issue, and after the warden supplied Arbitrum token data showing the dominant tokens all revert on zero-address transfers, the judge upgraded the severity from Medium to High.
Rubicon: The return value of `buyAllAmount` is incorrect
Rubicon's `buyAllAmount` on the order-book `RubiconMarket` contract incorrectly deducts the trading fee twice when reporting the amount of pay tokens the caller spent. The loop computes `fill_amt` from the actual offer prices, but the final `calcAmountAfterFee(fill_amt)` pass subtracts the fee from the already-accumulated total, so the function returns a lower value than the real cost (e.g. 9,000 USDC reported instead of 10,000 spent at a 10% fee). Any integrator or downstream logic relying on this return value — such as checks against `max_fill_amount` — will base decisions on a fee-discounted figure that understates true spend. The judge upheld the finding as distinct from fee-calculation issues and confirmed the fix: stop applying the fee to the returned value.
All reports in this group
- Rubicon: Incorrect fee handling in `Position.sol's` Market `Buy`/`Sell` functionsLogic error$0
- Rubicon: `FeeWrapper` fails to handle ETH payment refundsLogic error$0
- Rubicon: First depositor bug on unmodified Compound forkFront-running / MEV$0
- Rubicon: Due to the loss of precision, `openPosition` will make the user's leverage higher than expectedInteger overflow/underflow$0
- Rubicon: Calling `Position._marketSell` function compares `fill_amt` that includes fee to `min_fill_amount` that does not include feeLogic error$0
- Rubicon: No deadline parameter in `sellAllAmount()` and `buyAllAmount()` functions:Front-running / MEV$0
- Rubicon: Both buyAllAmountWithLeverage and sellAllAmountWithLeverage always revertLogic error$0
- Rubicon: User can possess less value than before when `V2Migrator.migrate` function is called to give up `bathTokenV1` tokens and hold `bathTokenV2` tokensLogic error$0
- Rubicon: `Position._borrowLimit` doesn't use exisiting collateral in case if user doesn't have any `_bathToken`Logic error$0
- Rubicon: The ````_matcho()```` is not implemented properlyLogic error$0
- Rubicon: `RubiconMarket: buy()` may not take any fee for tokens with low decimal precisionLogic error$0
- Rubicon: Calling `ExpiringMarket.stop` and `ExpiringMarket.isClosed` functions cannot pause any functionlities of the marketLogic error$0
- Rubicon: `RubiconMarket._buys` will not work for V1 offers due to the reversion in `cancel` method.Logic error$0
- Rubicon: Missing a check for minimum sell amount at the `make` functionLogic error$0
- Rubicon: Position doesn't distribute rewards to usersLogic error$0
- Rubicon: An attacker can steal all tokens of users that use `FeeWrapper`Logic error$0
- Rubicon: RubiconMarket `batchOffer` and `batchRequote` make offers as self; complete loss of funds for some types of tokens, for example WETHLogic error$0
- Rubicon: Incorrect calculations can occur when calling `Position._marketBuy` and `Position._marketSell` functions that do not include maker fee in `_fee`Logic error$0
- Rubicon: The curve of short leverage position is not smooth and may cause users to open positions that are different from expectationsLogic error$0
- Rubicon: Zero reward rate calculation impedes low-decimals token distributionsLogic error$0
- Rubicon: Use of `block.number` leads to incorrect interest calculationsLogic error$0
- Rubicon: Attack on rounding errors to get risk free profitInteger overflow/underflow$0
- Rubicon: Potential infinite loop in `_borrowLimit` functionLogic error$0
- Rubicon: REENTRANCY ATTACK POSSIBLE IF THE `_feeTo` IS A MALICIOUS CONTRACT IN `FeeWrapper._chargeFeePayable()` FUNCTIONReentrancy$0
- Rubicon: Users might get less assets than expected upon migration due to price manipulation attacksOracle manipulation$0
- Rubicon: A liquidated position possibly cannot be closedLogic error$0
- Rubicon: The last borrowed asset will not be collateralized and the user may be liquidated due to insufficient collateralLogic error$0
- Rubicon: Some offers can't be cancelledLogic error$0
- Rubicon: Fee inclusivity calculations are inaccurate in `RubiconMarket`Logic error$0
- Rubicon: `RubiconMarket` checks slippage incorrectlyLogic error$0
- Rubicon: Reward accounting is incorrect in `BathBuddy` contractLogic error$0
- Rubicon: An attacker can steal all `RubiconRouter` fundsLogic error$0
- Rubicon: Low level calls to accounts with no code will succeed in `FeeWrapper`Logic error$0
- Rubicon: Cannot close leveraged positionsLogic error$0
- Rubicon: Calling `Position._marketBuy` and `Position._marketSell` functions that calculate `_fee` by dividing by `10000` can cause incorrect calculationsLogic error$0
- Rubicon: Some positions will get liquidated immediatelyLogic error$0