Here’s how Octane found a critical vulnerability in MUX Protocol that put more than $8 million of user funds at risk, and why human-AI iterative analysis is where cybersecurity is headed.
An $8M Mux-Up: How Octane’s AI Found a Critical Vulnerability in MUX Protocol
Here’s how Octane found a critical vulnerability in MUX Protocol that put more than $8 million of user funds at risk, and why human-AI iterative analysis is where cybersecurity is headed.
Octane found a critical vulnerability in MUX Protocol that put more than $8 million of user funds at risk. We disclosed it, MUX patched it, and we (briefly) took top spot on the Immunefi leaderboard for 2026 as a result. This is the story behind that finding: how Octane uncovered the bug, where a human touch added major value, and what this all means for security research now and in the near future.
Why MUX
Our in-house security researcher chose MUX partly because he already had some familiarity with the codebase. Before joining Octane, he had found issues in a previous version of the protocol, and the MUX team had been responsive during the validation and patching phases. Thinking pragmatically, the protocol sat in a sweet spot: large enough to matter, but not so overexposed that every bounty hunter on earth was already combing through it.
There were also technical reasons to think it was worth a shot. MUX v3 was still a new enough deployment that it likely had not yet received the full weight of open-source scrutiny, and its design relied on some complicated math.
At the same time, parts of the system relied on an offchain broker to finalize user actions. That created a level of ambiguity that can make bounty hunting unattractive. It’s often possible to find something that looks definitively dangerous onchain, only to be told that the trusted offchain sequencer or whitelisted broker would never allow it in practice. That can turn a deep technical disclosure into an argument about getting paid – a headache every whitehat will know.
That mattered here. One reason Octane was so effective is that it let our researcher look through a set of candidate findings first, before deciding which ones were worth spending real time and energy on investigating further. This is an iterative, multi-step process that specifically focuses the AI where its attention is most productive.
Scanning for Signal
The process started with an initial scan, shaped by some high-level assumptions about where vulnerabilities were most likely to surface. At that stage, Octane’s output was raw signal, a set of leads at varying levels of confidence. That’s fine, the goal was to surface enough candidate findings that a human researcher could then identify the most promising threads to pull on.
The first human step after kicking off the scan was triage. Our researcher went through the results and looked for the findings that were both technically plausible and economically impactful. When it comes to bug bounties, it’s imperative to demonstrate exactly what it lets an attacker do, how their attack works, and why the impact falls into a specific severity category.
In this case, one thing stood out: multiple independent analyses kept converging on the same bug. This often means the model has locked onto something real in the architecture rather than hallucinating a one-off edge case. The core issue here was not subtle in that sense; Octane was consistently surfacing the same failure mode through slightly different paths.
Target Acquired
The vulnerable path came up in MUX’s liquidity removal flow. Pool.removeLiquidity calculated liquidityFeeCollateral in args.token, but the downstream transfer used the pool’s _collateralToken instead.
That meant a withdrawal fee that should have been a small USDC-denominated amount could instead be transferred out as WBTC. Our final submission described two viable attack paths: a simpler LP-price inflation route and a more complex route that amplified profit via referral rebates and repeated draining behavior.
The wider problem wasn’t just that the wrong asset left the pool – though the counterparty you just acquired a Bitcoin at a 99.99% discount from might disagree. With these mismatched transfers, the protocol’s internal accounting would also drift away from its actual, rapidly-diminishing balances. liquidityBalances would no longer match balanceOf, LP pricing would inflate, and later users could be left holding the bag while earlier withdrawers extracted value against a false NAV.
This created insolvency risk and led directly to paths with losses exceeding $1 million, as user funds were at risk across other affected pools.
Proof of Work
This is where the human work really began. Octane found the issue, but it did not automatically turn it into a ready-to-report bug bounty submission.
Our researcher spent multiple days figuring out how to express the issue in maximum-impact terms, writing PoCs, calculating accounting balances, and preparing a report detailed enough that the protocol team could only accept its findings.
If we had submitted the raw issue without showing the full exploitability and economic consequences, it likely would have been treated as a much lower-impact bug. Instead, the report showed the full scale of the problem.
Still, we had to conclusively prove the point. Only because our researcher knew the code, the exploit path, and the impact model in extreme detail were we able to effectively defend the bug’s true impact and severity.
This is one of the clearest examples of why even AI-native security analysis for bug bounties still benefits from a human in the loop.
Why MUX Matters
The MUX process worked the way security is going to work more and more often, at larger and larger scale.

In this workflow, AI-native security analysis finds the lead and human researchers test, validate, and turn that lead into a final report. This is the most intensive level of security analysis, using the most powerful reasoning models.
We’re also pleased to report that MUX Protocol is now an Octane user. After the successful bug bounty report we’re looking forward to continuing to work with the team on securing MUX, Arbitrum, and all mission-critical software at scale.
For the security researchers and committed readers who’ve made it to the end of this blog and want even more technical detail, below is the submission writeup that got this confirmed as a critical vulnerability.
Brief
- Pool.removeLiquidity calculates liquidityFeeCollateral in args.token, but transfers it in _collateralToken.
- This leads to excessive rewards to rebate and veMUX holders.
- It also breaks internal accounting: liquidityBalances stop matching .balanceOf ⇒ inflated LP price ⇒ insolvency.
Vulnerability Details
There are at least two viable attack paths:
- Simple: buy LP (addLiquidity), inflate LP price, sell LP.
- More complex: maximize profit via referral rebates, then repeat until collateral is drained. The attacker can either wait until there is more USDC (and other cheap tokens) in the pool, or force the condition themselves by intentionally taking losses on a long (the attacker can close and reopen positions until a loss occurs).
Both are described on the largest WBTC pool (0x5BDc5c2d8b5b50072906632f678AfA054E8f257d) using LiquidityOrderParams.token = USDC.
Simple attack (mostly LP price inflation)
- Attacker: buys as much LP as possible (placeLiquidityOrder with isAdding=true, then waits for the broker to fillLiquidityOrder).
- (I used account2 in the PoC to show the profit from both steps separately.)
- Attacker: calls OrderBook.placeLiquidityOrder to remove liquidity using LiquidityOrderParams.token != pool.collateralToken for all available USDC.
- This is explicitly allowed in LibOrderBook2.placeLiquidityOrder.
- The only check in the !isAdding branch is _validateCollateral:
- that the collateral is in the list of allowed collaterals
- not necessarily that orderParams.token == collateralToken (as in the isAdding branch)
- The only check in the !isAdding branch is _validateCollateral:
- (An attacker can use several orders with several tokens, as long as they are cheap enough (tested at ~ $1), to increase LP inflation. Only USDC is used in the PoC for simplicity.)
- Example: if an attacker withdraws $10k USDC / sUSDe / etc.:
- The fee for the largest WBTC pool is set to 5e14 ⇒ 0.05%
- (pool).configValue(MCP_LIQUIDITY_FEE_RATE)
- Even though the fee should be $5, it becomes 5 WBTC (explained in the next “Broker” step).
- The fee for the largest WBTC pool is set to 5e14 ⇒ 0.05%
- Example: if an attacker withdraws $10k USDC / sUSDe / etc.:
- This is explicitly allowed in LibOrderBook2.placeLiquidityOrder.
- Broker: as expected, calls OrderBook.fillLiquidityOrder.
- _fillRemoveLiquidityOrder → pool.removeLiquidity
- collateralPrice is for USDC
- collateralAmount is for USDC
- liquidityFeeCollateral is in USDC
- ❗ _distributeFee accepts liquidityFeeCollateral (feeCollateral) in USDC
- but we always transfer _collateralToken (WBTC), even though the amount passed in was in USDC
- ❗ 2.5% goes to the attacker-specified address (rebate = attacker)
- ❗ 2.5% goes to the fee payer (LP = attacker)
- Remaining 95%: 70% back to LP, 30% to veMUX
- This increases LP price because:
- CollateralPool._distributeFee sends WBTC out but does not decrement _liquidityBalances (CollateralPool.sol, line 622)
- Mux3FeeDistributor then sends the LP share back via OrderBook.donateLiquidity (Mux3FeeDistributor.sol, line 266 → LibOrderBook.sol, line 42), which calls CollateralPool.receiveFee and adds to _liquidityBalances (CollateralPool.sol, line 393)
- So the internal WBTC balance can increase, even while the real WBTC balanceOf(pool) drops from the fee transfer
- _fillRemoveLiquidityOrder → pool.removeLiquidity
- Attacker: sells LP at an inflated price.
- uint256 lpPrice = _nav(aumUsd);
- aumUsd depends on _liquidityBalances (see _aumUsdWithoutPnl)
- uint256 lpPrice = _nav(aumUsd);
More complex attack (more profit from referral fees)
Preparation
- Attacker: calls ReferralManager.registerReferralCode and ReferralManager.setRebateRecipient to receive 2.5% of fees paid to a desired address (tier 0).
- Attacker: calls OrderBook.placeLiquidityOrder and adds liquidity normally (expected behavior).
- Wait for LibOrderBook._liquidityLockPeriod(orderBook).
Exploit
- ❗ Attacker: calls OrderBook.placeLiquidityOrder to remove liquidity with LiquidityOrderParams.token != pool.collateralToken.
- This is explicitly allowed in LibOrderBook2.placeLiquidityOrder; there is no check in the !isAdding branch.
- Broker: as expected, calls OrderBook.fillLiquidityOrder.
- _fillRemoveLiquidityOrder → pool.removeLiquidity
- collateralPrice is for USDC
- collateralAmount is for USDC
- liquidityFeeCollateral is in USDC
- ❗ _distributeFee accepts liquidityFeeCollateral (feeCollateral) in USDC
- but we always transfer _collateralToken (WBTC), even though the amount passed in was in USDC
- ❗ 2.5% goes to the attacker-specified address (rebate = attacker)
- ❗ 2.5% goes to the fee payer (LP = attacker)
- Remaining 95%: 70% back to LP, 30% to veMUX
- _fillRemoveLiquidityOrder → pool.removeLiquidity
Result
- If an attacker withdraws $10k USDC:
- The fee for the largest WBTC pool is set to 5e14 ⇒ 0.05%
- (pool).configValue(MCP_LIQUIDITY_FEE_RATE)
- Even though the fee should be $5, it becomes 5 WBTC
- assuming $100k / WBTC, 2.5% × $500k = $12.5k goes to the attacker as profit
- the attack can be repeated until the pool is drained:
- in the preparation step, deposit $1m in WBTC
- 100 × 10,000 USDC withdrawals ⇒ $12.5k × 100 = $1.25m drained
- The fee for the largest WBTC pool is set to 5e14 ⇒ 0.05%
We’ll be happy to explain any step in more detail or simplify the PoC if needed.
Impact
Almost full drain of TVL on many pools.
- breaks internal accounting: liquidityBalances are larger than real balances (.balanceOf) ⇒ LP price is too high ⇒ insolvency (first withdrawers get more; last users can’t withdraw)
- more than $1.1m in the simple attack
- about $2.5m in the more complex attack
- excessive rewards to veMUX holders from inflated LP value
- about 30% of the pool is lost with each removeLiquidity call; in the PoC, it is the remaining pool WBTC, since removeLiquidity was called many times
- referral fees go to the attacker
- $1m in the complex attack
- $144k in the simple attack
The total impact exceeds $1 million in both the simple and complex cases.



