# Migration: no check that user-supplied proposalId and vault match

Migration.join/leave key accounting only on proposalId, not vault, letting an attacker deposit worthless tokens and withdraw another vault's valuable tokens.

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

**Target:** Migration.sol join/leave functions
**Root cause:** userProposalFractions is keyed only by proposalId and msg.sender, not by vault, while token resolution and migrationInfo accounting use the caller-supplied vault; the two are never cross-checked.
**Steps:**
1. Alice deposits 100 TOKEN (Vault A) into Migration for proposalId 1.
2. Attacker creates Vault B with worthless FERC1155 token ERIS and mints 100 to himself.
3. Attacker calls `join(proposalId=1, vault=VaultB, amount=100)`; contract pulls ERIS and sets `userProposalFractions[1][attacker] += 100`.
4. Attacker calls `leave(proposalId=1, vault=VaultA, amount=100)`; contract resolves TOKEN from Vault A, reads 100 from userProposalFractions, deducts from migrationInfo[VaultA][1], and sends 100 TOKEN to attacker.
**How found:** Code review of Migration.sol: noticed token resolution and migrationInfo use the user-supplied vault while userProposalFractions is keyed only by proposalId, implying the pair is never validated.
**Exploitation:** Attacker needs only a self-created vault with a worthless FERC1155 token. By depositing worthless tokens under a victim's proposalId and then withdrawing against the victim's vault, the attacker drains tokens deposited by other users into uncommitted proposals.
**Insight:** When a function takes two identifiers that jointly define state (vault + proposalId), check whether per-user accounting keys on both or only one; mismatched keying lets an attacker supply a cheap asset on deposit and a valuable one on withdrawal.
