# Fund will be stuck if a buyout is started while there are pending migration proposals

Migration.sol leave/withdrawContribution only check buyout state, so a third-party buyout started during a pending migration proposal permanently locks contributor funds.

- Payout: Contest reward
- Severity: high
- Program: Fractional
- Credited: shenwilly
- Disclosed: 2022-09-27
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2022-07-fractional-findings/issues/230
- Library page: https://bugbountylibrary.com/r/c4%3A2022-07-fractional%3AH-14
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:chained technique:source-review vuln:access-control vuln:business-logic

**Target:** Migration.sol / Buyout.sol vault modules (Solidity)
**Root cause:** Migration functions gate on buyout auction state (INACTIVE) rather than checking whether the buyout proposer is Migration.sol itself, so any external buyout blocks leave/withdrawContribution.
**Steps:**
1. Bob calls `migrationModule.propose(vault, modules, plugins, selectors, TOTAL_SUPPLY*2, 1 ether)`
2. Bob calls `migrationModule.join{value: 0.5 ether}(vault, 1, HALF_SUPPLY)`
3. Alice calls `buyoutModule.start{value: 1 ether}(vault)` making buyout state LIVE
4. Bob calls `migrationModule.leave(vault, 1)` -> reverts `InvalidState(0,1)`
5. Alice calls `buyoutModule.end(vault, burnProof)` after rejectionPeriod -> state SUCCESS
6. Bob calls `leave`/`withdrawContribution` -> reverts `InvalidState(0,2)`, funds stuck
**How found:** Code review of Migration.sol state checks: noticed functions only verify buyout state is INACTIVE and never check the buyout proposer, then reasoned about a third party starting a buyout mid-proposal.
**Exploitation:** Any party starts a buyout auction on a vault that has a pending migration proposal; contributors can no longer call leave or withdrawContribution because those functions require buyout state INACTIVE. If the buyout succeeds, contributed ETH is permanently locked.
**Insight:** When two modules share a state machine, check whether guards verify the actor/owner of that state, not just the state value; a third party can drive the shared state to block your module's exit paths.
