# Fei Protocol Flashloan Vulnerability Bugfix Review

Fei Protocol's allocate() deposited PCV into Uniswap at oracle price with 100% slippage; a flash-loan-distorted pool plus constructor bypass of nonContract guard drained up to 60,000 ETH.

- Payout: $800,000
- Severity: critical
- Program: Fei Protocol
- Credited: Alexander Schlindwein
- Disclosed: 2021-05-14
- Write-up quality: 9/10
- Original: https://immunefi.com/blog/bug-fix-reviews/fei-protocol-flashloan-vulnerability-bugfix-review/
- Library page: https://bugbountylibrary.com/r/blog%3Aimmunefi-com-blog-bug-fix-reviews-fei-protocol-flashloan-vulnerability-bugfix-review
- Tags: domain:web3 impact:funds-loss kind:bounty platform:blog platform:immunefi sev:critical tech:evm tech:solidity technique:chained vuln:access-control vuln:business-logic vuln:flash-loan vuln:oracle-manipulation

**Target:** EthBondingCurve / EthUniswapPCVDeposit allocate() on Uniswap V2 ETH/FEI pool
**Root cause:** allocate() called addLiquidityETH at the ETH/USD oracle price with 100% slippage tolerance, so a flash-loan-distorted pool let the protocol deposit far more ETH than FEI. The nonContract guard (Address.isContract) was bypassable from a contract constructor.
**Steps:**
1. Flash loan WETH from Aave (d+b)
2. Dump d WETH into Uniswap ETH/FEI pool via `swapExactTokensForTokens` to make FEI expensive/ETH cheap
3. Buy FEI on bonding curve with b ETH at protocol price $1.01 via `purchase{value: b}`
4. Deploy dummy contract whose constructor calls `bondingCurve.allocate()` to bypass nonContract modifier
5. allocate() invokes addLiquidityETH at oracle price with 100% slippage, depositing PCV ETH into distorted pool
6. Swap bought FEI back to WETH to capture excess ETH deposited
7. Repay Aave flash loan plus premium
**How found:** Researcher noticed allocate() was permissionless and deposited at oracle price with 100% slippage, and that the nonContract guard using Address.isContract returns false during contract construction, enabling bypass.
**Exploitation:** Attacker flash-loans WETH, splits funds optimally (d dumped into pool, b spent on bonding curve) computed via GEKKO NLP solver, distorts the Uniswap pool, triggers allocate() from a constructor to bypass the contract check, causing the protocol to deposit PCV ETH at oracle price into the skewed pool, then swaps FEI back for WETH and repays the loan, netting up to 60,000 ETH (capped by ~1M ETH flash-loan liquidity).
**Escalation:** Optimal split of flash-loaned capital between pool dump and bonding-curve purchase maximizes profit; scaling flash-loan size across multiple providers increases drain.
**Insight:** extcodesize-based isContract checks return false for contracts still in their constructor — any 'no contracts' guard can be bypassed by calling from a constructor. Also, addLiquidity with 100% slippage against an oracle price is exploitable whenever the pool can be skewed by a flash loan.
