# Steal NFTs from a Vault, and ETH + Fractional tokens from users.

Migration.withdrawContribution refunds ETH/fractions without decrementing totalEth/totalFractions, letting an attacker inflate a proposal to steal vault funds and NFTs.

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

**Target:** Migration.sol proposal join/withdraw/commit flow
**Root cause:** withdrawContribution refunds a user's ETH and fraction tokens but fails to decrement proposal.totalEth and proposal.totalFractions, unlike join/leave, so repeated join+withdraw inflates the proposal's recorded totals.
**Steps:**
1. Wait until >=50% of fractional token supply is stacked into one or more proposals in the vault.
2. Create an evil proposal with malicious modules.
3. Loop `join{value: 10 ether}(vault, 2, 25)` then `withdrawContribution(vault, 2)` several times, then a final `join{value: 10 ether}(vault, 2, 101)` to inflate totalEth/totalFractions to match vault totals.
4. Call `commit(vault, 2)` to pull all vault ETH and fractions into the evil proposal and start it.
5. Proposal now holds >51% supply and stolen ETH; execute evil module to take vault NFTs.
**How found:** Code review of Migration.sol join/leave vs withdrawContribution accounting; noticed withdrawContribution omits totalEth/totalFractions updates that join/leave perform, hypothesized repeated join+withdraw inflates proposal totals.
**Exploitation:** Attacker inflates their proposal's recorded ETH/fraction totals via join/withdraw loop using only ~10 ETH real capital, then commits to drain the vault's pooled ETH and fractional tokens into their proposal, reaching >51% supply to pass and execute malicious modules stealing NFTs; legit proposal is invalidated since only one proposal can be LIVE and funds are gone.
**Escalation:** Chained inflation bug into proposal takeover: >51% supply plus stolen ETH lets attacker pass evil modules to seize vault NFTs; also manipulates Buyout depositAmount/msg.value pricing to deter victim counter-buyouts during REJECTION_PERIOD.
**Insight:** When a contract has paired deposit/withdraw functions, diff their state updates: any accounting variable (totals, shares) updated on deposit but not on refund is an inflation primitive—loop deposit+refund to inflate recorded balances and drain pooled funds.
