# 88mph Function Initialization Bugfix Review

Unprotected init() on 88mph pool deposit NFT contracts let anyone re-initialize, take ownership, burn/mint user NFTs and steal $6.5m in deposits.

- Payout: $42,069
- Severity: critical
- Program: 88mph
- Credited: Ashiq Amien
- Disclosed: 2021-06-14
- Write-up quality: 7/10
- Original: https://immunefi.com/blog/bug-fix-reviews/88mph-function-initialization-bugfix-review/
- Library page: https://bugbountylibrary.com/r/blog%3Aimmunefi-com-blog-bug-fix-reviews-88mph-function-initialization-bugfix-review
- Tags: domain:web3 impact:funds-loss kind:bounty platform:blog platform:immunefi sev:critical tech:evm tech:solidity technique:source-review vuln:access-control vuln:business-logic

**Target:** Solidity pool deposit NFT contracts (init/mint/burn)
**Root cause:** init() lacked onlyOwner and initializer modifiers, so it was callable repeatedly by anyone, allowing arbitrary takeover of NFT contract ownership.
**Steps:**
1. Identify vulnerable pool deposit contracts (yaLINK, CRV:STETH, CRV:RENWBTC) with public init().
2. Call `nft.init(address(this), "", "")` to become owner of the deposit NFT contract.
3. Use ownership to `nft.burn(_depositID)` and `nft.mint(address(this), _depositID)` to seize a victim's deposit NFT.
4. Call `pool.earlyWithdraw(_depositID, _fundingID)` or `pool.withdraw(...)` to redeem the underlying stablecoin.
5. Transfer drained stablecoin to attacker address.
**How found:** Code review of pool deposit contracts revealed init() missing onlyOwner and initializer modifiers, making it publicly re-callable.
**Exploitation:** Attacker re-initializes the NFT contract to gain ownership, then burns and re-mints any user's deposit NFT to themselves and calls withdraw/earlyWithdraw on the pool to redeem underlying tokens, extracting up to $6.5m mostly in crvRenWBTC.
**Escalation:** Ownership of the NFT contract also allowed minting arbitrary NFTs, which could temporarily or permanently break pool _deposit()/_fund() functions.
**Insight:** On upgradeable/initializable contracts, check that init() has both an access guard and an initializer/reinitializer guard; a public init() on an NFT or vault contract is effectively an ownership-takeover primitive over all user positions.
