# Fei Protocol Vulnerability Bugfix Review

Fei's buy-reward minting plus stale Uniswap reserves let an attacker collect buy rewards and dodge sell burn penalties, draining ~1410 ETH from the WETH/FEI pool.

- Payout: $300,000
- Severity: critical
- Program: Fei Protocol
- Credited: 0xRevert
- Disclosed: 2021-04-10
- Write-up quality: 8/10
- Original: https://immunefi.com/blog/bug-fix-reviews/fei-protocol-vulnerability-bugfix-review/
- Library page: https://bugbountylibrary.com/r/blog%3Aimmunefi-com-blog-bug-fix-reviews-fei-protocol-vulnerability-bugfix-review
- Tags: domain:web3 impact:funds-loss kind:bounty platform:blog platform:immunefi sev:critical tech:evm tech:solidity technique:chained technique:source-review vuln:business-logic vuln:oracle-manipulation

**Target:** Uniswap V2 WETH/FEI pair and Fei incentive/PCV contracts
**Root cause:** Sell-penalty ('below peg') checks read Uniswap pair reserves, which only update on swap, so plain ERC-20 transfers that push price below peg incur no burn; buy rewards are minted with no disincentive for overshooting the peg.
**Steps:**
1. Call `UniswapV2Pair.swap` to buy FEI with WETH, pushing price above peg and collecting a buy reward (purchasedFei > buyAmount).
2. Drip FEI back into the pair via `Fei.transfer` (not swap) in chunks; reserves stay stale so no burn penalty is applied.
3. Call `UniswapV2Pair.swap` again to sell FEI for WETH; this updates reserves and cashes out more WETH than spent.
4. Variant: instead of dripping, call `pcvcontroller.reweight()` after the buy to restore peg, then transfer FEI and swap out, bypassing the faulty nonContract modifier.
**How found:** Researcher noticed sell-penalty computation depends on Uniswap pair reserves, which only refresh on swap, so non-swap transfers evade the burn; buy rewards also lack a penalty for overshooting peg.
**Exploitation:** Attacker needs large WETH capital (flash-loanable). Buy FEI past peg for a reward, return FEI via transfers that don't trigger burn because pair reserves are stale, then swap back to WETH for a riskless profit at LPs' expense; repeatable to drain ~1410 ETH.
**Escalation:** Repeatable loop drains the pool; variant uses reweight() to restore peg instead of dripping FEI.
**Insight:** When a protocol derives price/penalty state from AMM reserves, check whether plain token transfers (which don't sync reserves) can move price without triggering the penalty logic; also look for asymmetric incentives (reward on buy, penalty only on sell).
