# PDZ: spot-price manipulation in burnToHolder drains BNB rewards

PDZ's burnToHolder priced BNB rewards via Uniswap getAmountsOut, letting an attacker flash-swap to inflate PDZ price and drain 3.3 BNB.

- Payout: Real-world hack
- Severity: high
- Program: PDZ
- Credited: DeFiHackLabs
- Disclosed: 2025-08-15
- Write-up quality: 6/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2025-08/PDZ_exp.sol
- Library page: https://bugbountylibrary.com/r/dhl%3A20250815-pdz
- Tags: domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:high tech:evm tech:solidity technique:chained vuln:flash-loan vuln:oracle-manipulation

**Target:** BSC token reward contract (TbBuild) using PancakeSwap router pricing
**Root cause:** burnToHolder computes BNB rewards from uniswapRouter.getAmountsOut on the live PancakeSwap PDZ/WBNB pool, so the reward amount is directly manipulable by swapping in the same transaction.
**Steps:**
1. Flash-borrow 10 WBNB from PancakeSwap pair `0x231d9e...542C` via `swap(10 ether,0,this,hex"00")`.
2. In pancakeCall, approve router and swap 10 WBNB -> PDZ via `swapExactTokensForTokensSupportingFeeOnTransferTokens`, pumping PDZ price.
3. Call `tbBuild.burnToHolder(5467668273, address(0))` then `tbBuild.receiveRewards(address(this))` to claim inflated BNB reward.
4. Swap remaining PDZ back to WBNB via `swapExactTokensForETHSupportingFeeOnTransferTokens`.
5. Repay flash loan 10.25 WBNB + 1 wei to the pair.
**How found:** Recognized that burnToHolder's reward calculation calls uniswapRouter.getAmountsOut against a spot pool, making the payout a function of manipulable spot price.
**Exploitation:** Single-transaction flash loan: borrow WBNB, buy PDZ to spike pool price, trigger burnToHolder/receiveRewards which reads getAmountsOut at the manipulated price, then sell PDZ and repay the loan, netting 3.3 BNB.
**Insight:** When a contract pays out rewards denominated in a base asset but priced via router.getAmountsOut on a spot pool, the payout is a free money printer: flash-swap to move the pool, trigger the reward function, unwind. Grep reward/claim functions for getAmountsOut/getReserves.
