# Incorrect supply fund transferral in function leave() can be exploited to drain locked collateral source funds in subnet actor contract

leave() refunds genesis supply deposits from collateralSource instead of supplySource, letting an attacker drain higher-value collateral by preFund then leave.

- Payout: Contest reward
- Severity: high
- Program: Recall
- Credited: sin1st3r__
- Disclosed: 2026-03-13
- Write-up quality: 7/10
- Original: https://code4rena.com/reports/2025-02-recall#h-05
- Library page: https://bugbountylibrary.com/r/c4%3A2025-02-recall%3AH-05
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** SubnetActorManagerFacet contract (leave/preFund/preRelease)
**Root cause:** leave() calls s.collateralSource.transferFunds for genesisBalance refunds instead of s.supplySource, mixing supply and collateral accounting.
**Steps:**
1. Deploy subnet with supplySource = cheap ERC20 ($1) and collateralSource = native ETH ($2000).
2. Attacker calls `preFund()` depositing 10 supplySource ERC20 tokens.
3. Attacker calls `join()` staking minimal collateralSource ETH.
4. Attacker calls `leave()`; contract transfers 10 ETH (collateralSource) for genesisBalance plus staked ETH back.
5. Attacker nets ~$19,990 profit; subnet collateral drained.
**How found:** Code review of leave() refund path; noticed it used collateralSource while preRelease() correctly uses supplySource for the same genesisBalance accounting.
**Exploitation:** Attacker deposits cheap supply tokens via preFund, joins with minimal stake, then calls leave() which refunds genesisBalance from collateralSource (ETH), extracting far more value than deposited.
**Insight:** When a contract has parallel funding sources (supply vs collateral), audit every refund/withdraw path for source mismatch against the deposit path; compare sibling functions like preRelease() to spot the inconsistency.
