# Penpie: fake-market reentrancy drains $27M in staking rewards

Attacker registered a fake Pendle market in Penpie, then exploited reentrancy in reward claiming to inflate rewards and drain ~$27M in agETH/rswETH.

- Payout: Real-world hack
- Severity: critical
- Program: Penpiexyz_io
- Credited: DeFiHackLabs
- Disclosed: 2024-09-03
- Write-up quality: 8/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2024-09/Penpiexyzio_exp.sol
- Library page: https://bugbountylibrary.com/r/dhl%3A20240903-penpiexyzio
- Tags: domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:critical tech:evm tech:solidity technique:chained vuln:accounting-error vuln:flash-loan vuln:reentrancy vuln:reward-distribution

**Target:** Pendle/Penpie staking reward accounting (MasterPenpie, PendleStaking, PendleMarketDepositHelper)
**Root cause:** Penpie trusted attacker-registered Pendle markets and computed rewards from market-supplied getRewardTokens/rewardIndexesCurrent without validating the market, and reward claiming was reentrant, letting a fake market inflate reward balances.
**Steps:**
1. Deploy Attacker contract implementing fake Pendle market interface (assetInfo, exchangeRate, getRewardTokens, rewardIndexesCurrent, claimRewards).
2. Call `PendleYieldContractFactory.createYieldContract(attacker, expiry, true)` to mint PT/YT for the fake asset.
3. Call `PendleMarketFactoryV3.createNewMarket(PT, ...)` to create PENDLE_LPT, then `PendleMarketRegisterHelper.registerPenpiePool(PENDLE_LPT)` to register it in Penpie.
4. Mint YT/PT/LP to self and `depositMarket(PENDLE_LPT, ~1e18)` into PendleMarketDepositHelper.
5. Roll one block so PendleMarketV3 lastRewardBlock check passes.
6. Flash loan full agETH and rswETH balances from Balancer Vault.
7. In receiveFlashLoan: call `PendleStaking.batchHarvestMarketRewards([PENDLE_LPT], 0)` and `MasterPenpie.multiclaim([PENDLE_LPT])`, triggering the fake market's `claimRewards` reentrancy hook.
8. Inside claimRewards, add liquidity via `PendleRouterV4.addLiquiditySingleTokenKeepYt` for real markets 0x6010 and 0x038c, deposit LPs, and re-enter reward accounting to inflate owed rewards.
9. Withdraw real LPs, redeem inflated rewards, repay flash loan, keep agETH/rswETH profit.
**How found:** Likely spotted that Penpie's registerPenpiePool accepted arbitrary Pendle markets and that reward computation trusted market-reported token lists and indexes, making a self-registered market a controllable oracle for reward math.
**Exploitation:** Attacker flash-borrowed entire Balancer agETH and rswETH pools, registered a malicious Pendle market whose claimRewards callback re-entered Penpie's reward pipeline to credit fake LP deposits against real reward pools, then withdrew and redeemed the inflated rewards, repaying the loan and keeping ~11,113 ETH.
**Escalation:** Chained fake-market registration + reentrancy + flash loan to amplify a reward-accounting bug into a full drain of staking rewards across two assets.
**Insight:** When a protocol lets anyone register a pool/market and then trusts that pool's self-reported token list and reward indexes during harvest, a fake pool with a reentrant claimRewards callback can mint arbitrary reward debt against real reward tokens.
