# Vault could `rebalance()` before funds arrive from xChainController

Cross-chain message ordering in Connext lets receiveFunds() execute before xTransfer settles, so anyone can call rebalance() on a vault with incomplete funds, reducing rewards.

- Payout: Contest reward
- Severity: medium
- Program: Derby
- Credited: Ch_301
- Disclosed: 2022-10-17
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2023-01-derby-judging/issues/268
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-01-derby%3AM-19
- Tags: domain:web3 kind:contest platform:sherlock sev:medium tech:evm technique:source-review vuln:accounting-error vuln:business-logic vuln:race-condition

**Target:** MainVault / XProvider cross-chain rebalancing flow
**Root cause:** pushFeedbackToVault() and xTransfer() are separate Connext messages that can land in different Merkle roots or be delayed by slippage, so receiveFunds() can fire before the asset transfer settles; rebalance() has no check that expected funds actually arrived.
**Steps:**
1. xChainController calls sendFundsToVault() -> xTransferToVaults()
2. xTransferToVaults() calls pushFeedbackToVault() (slow path) then xTransfer() (fast or slow path)
3. If xTransfer() is delayed (high slippage retry) or batched into a later Merkle root, pushFeedbackToVault() executes first, invoking receiveFunds() on the vault
4. Before xTransfer() settles, call `rebalance()` on the vault
5. Vault rebalances using reservedFunds/liquidityPerc only, missing the expected incoming funds
**How found:** Reading the xTransferToVaults() flow, noticing pushFeedbackToVault() and xTransfer() are independent Connext messages; cross-referencing Connext docs on slow path, high slippage retries, and out-of-order Merkle root delivery to hypothesize receiveFunds() can precede the actual fund transfer.
**Exploitation:** Attacker observes receiveFunds() executed on the vault while the corresponding xTransfer() is still pending (slow path or later Merkle batch), then front-runs the settlement by calling rebalance(), causing the vault to rebalance with a smaller-than-expected balance and reducing rewards.
**Insight:** When a protocol sends a state-sync message and a value-transfer message as separate cross-chain calls, check whether the receiver's state-changing entrypoints (rebalance, claim, settle) can be invoked between them; Connext batches messages into 30-min Merkle roots so ordering is not guaranteed.
