# Proposer can start a perpetual buyout which can only end if the auction succeeds and is not rejected

Proposer re-enters start() from receive() during failed buyout refund, keeping buyoutInfo permanently LIVE and locking vault assets forever.

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

**Target:** Buyout.sol buyout module (start/end/_sendEthOrWeth)
**Root cause:** start() lacks reentrancy protection; when end() refunds a failed auction via _sendEthOrWeth, the proposer's receive() can call start() again, resetting buyoutInfo to LIVE before it can be set INACTIVE.
**Steps:**
1. Deploy malicious contract implementing onERC1155Received and a receive() that calls Buyout.start(vault, ...) with received ETH.
2. Call start() from the malicious contract to create a buyout proposal.
3. Ensure auction fails (<50% fractions sold) and rejection period passes.
4. Call end(); _sendEthOrWeth sends ETH to proposer contract, whose receive() re-enters start(), creating a new LIVE buyout.
5. Repeat: buyoutInfo[vault] never reaches INACTIVE, blocking all future proposals.
**How found:** Code reading of Buyout.sol: noted single buyoutInfo per vault (line 39), start() requires INACTIVE (lines 66-68), and _sendEthOrWeth refunds proposer (line 235) without reentrancy guard; hypothesized receive() callback could re-enter start().
**Exploitation:** Attacker deploys contract that re-enters start() on ETH receipt, initiates buyout, lets it fail, then any end() call auto-restarts the buyout, permanently locking vault assets unless other holders sellFractions to force success.
**Escalation:** Reentrancy makes griefing deterministic vs. the racy duplicate issues where another bidder could sneak in a tx.
**Insight:** When a refund path sends ETH to an attacker-controlled address, check whether the receiving callback can re-enter state-mutating functions that gate on the same state variable; a swallowed revert in the send helper does not prevent reentrancy.
