# Protocol loses fees because highWaterMark is updated every time someone deposit, withdraw, mint

Vault's highWaterMark resets on every deposit/withdraw/mint, letting anyone frontrun takeFees with a tiny deposit to zero out accrued performance fees.

- Payout: Contest reward
- Severity: high
- Program: Popcorn
- Credited: rvierdiiev
- Disclosed: 2023-09-07
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2023-01-popcorn-findings/issues/70
- Library page: https://bugbountylibrary.com/r/c4%3A2023-01-popcorn%3AH-11
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:solidity technique:source-review vuln:accounting-error vuln:business-logic vuln:fee-bypass

**Target:** ERC4626-style Vault contract (Vault.sol) performance-fee accounting
**Root cause:** syncFeeCheckpoint modifier unconditionally sets highWaterMark = convertToAssets(1e18) after every deposit/mint/withdraw, so the yield baseline is overwritten instead of only updating when fees are actually accrued.
**Steps:**
1. Strategy accrues yield so convertToAssets(1e18) > highWaterMark, making accruedPerformanceFee() > 0.
2. Attacker observes pending takeFees call (or simply calls deposit first).
3. Attacker calls `deposit(1, attacker)` on Vault; syncFeeCheckpoint runs post-call and sets `highWaterMark = convertToAssets(1e18)`.
4. Subsequent takeFees computes `shareValue - highWaterMark == 0`, so accruedPerformanceFee() returns 0 and protocol collects no fee.
**How found:** Read the fee-accrual design: accruedPerformanceFee compares shareValue to highWaterMark, then noticed syncFeeCheckpoint on deposit/mint/withdraw overwrites highWaterMark unconditionally, breaking the yield-tracking invariant; confirmed intended behavior with the sponsor.
**Exploitation:** Frontrun the fee-taking transaction with a minimal deposit (or any deposit/mint/withdraw) to reset highWaterMark to the current share value, causing accruedPerformanceFee to return zero and the protocol to forfeit all accrued performance fees to the attacker's timing advantage.
**Insight:** When a contract tracks a high-water mark or baseline for fee/profit accounting, check every code path that writes that variable—modifiers on user-facing deposit/withdraw/mint are a classic place where a baseline meant to persist gets clobbered, enabling frontrun-to-zero-fee attacks.
