# User can lose up to whole stake on vault withdrawal when there are funds locked in the strategy

ReaperVaultV2 burns full shares but caps payout to vault balance when strategy funds are locked, letting users lose up to entire stake beyond withdrawMaxLoss.

- Payout: Contest reward
- Severity: high
- Program: Ethos Reserve
- Credited: hyh
- Disclosed: 2023-05-02
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2023-02-ethos-findings/issues/288
- Library page: https://bugbountylibrary.com/r/c4%3A2023-02-ethos%3AH-02
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** ReaperVaultV2 vault withdraw / strategy liquidation
**Root cause:** _withdraw() rebases value down to token.balanceOf(address(this)) before the withdrawMaxLoss check, so the slippage guard compares against the already-truncated value instead of the original owed amount, while all requested shares are burned.
**Steps:**
1. Strategy holds funds; _liquidatePosition returns liquidatedAmount + loss < _amountNeeded, leaving lockedAmount = _amountNeeded - (liquidatedAmount + loss) > 0.
2. User calls vault withdraw for _shares worth 100 tokens; value = _freeFunds()*_shares/totalSupply() = 100.
3. _burn(_owner, _shares) burns all 100 tokens worth of shares.
4. value > token.balanceOf(vault) triggers strategy withdrawal; strategy returns only 10 (90 locked), reports loss=0.
5. vaultBalance=10; value reset to 10; require(totalLoss <= ((value+totalLoss)*withdrawMaxLoss)/PERCENT_DIVISOR) passes since totalLoss=0.
6. User receives 10 tokens but 100 tokens of shares burned.
**How found:** Code review of _withdraw() noticing value is overwritten with vault balance before the withdrawMaxLoss require, combined with strategy invariant liquidatedAmount + loss <= _amountNeeded allowing a locked-funds gap not counted as loss.
**Exploitation:** Triggered by any user withdrawal while a strategy has temporarily locked funds (liquidity squeeze); no attacker capital needed, loss realized by the withdrawing user, up to whole stake.
**Insight:** When a slippage/loss guard is checked after clamping the payout to available balance, the guard measures the clamped value not the original owed amount; check invariants where liquidatedAmount + loss can be strictly less than amountNeeded (locked funds) and ensure shares burned match value actually paid.
