# PTM: permissionless addLiquidity drains token-owned balances

PTM token's public addLiquidity spent the token contract's own PTM/USDT balances, letting an attacker flash-buy PTM, force liquidity at a manipulated ratio, and sell back for 552 USDT profit.

- Payout: Real-world hack
- Severity: medium
- Program: PTM
- Credited: DeFiHackLabs
- Disclosed: 2025-03-06
- Write-up quality: 6/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2025-03/PTM_exp.sol
- Library page: https://bugbountylibrary.com/r/dhl%3A20250306-ptm
- Tags: domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:medium tech:evm tech:solidity technique:chained vuln:access-control vuln:business-logic vuln:flash-loan

**Target:** BEP-20 token contract addLiquidity function on BSC
**Root cause:** addLiquidity(uint256,uint256) is externally callable with no access control and spends the PTM token contract's own PTM and USDT balances via Pancake Router, letting any caller dictate the liquidity ratio.
**Steps:**
1. Flash-borrow 70,000 USDT from Pancake V3 USDT/USDC pool
2. Approve Pancake Router for USDT and PTM
3. `router.swapExactTokensForTokensSupportingFeeOnTransferTokens(FLASH_AMOUNT,0,[USDT,PTM],...)` to buy PTM and inflate its price
4. Read `ptm.balanceOf(PTM_TOKEN)` and `usdt.balanceOf(PTM_TOKEN)` and call `ptm.addLiquidity(contractPtm, contractUsdt)` to dump the token contract's own balances into the pair at the skewed ratio
5. Sell all held PTM back to USDT via router
6. Repay flash loan plus fee0 to the pool
**How found:** Researcher noticed addLiquidity was externally exposed and spent the token contract's own balances without caller checks, making it manipulable via a flash-loan-funded price move.
**Exploitation:** Attacker flash-borrows USDT, buys PTM to move price, then calls the unprotected addLiquidity which spends the token contract's own reserves into the PTM/USDT pair at the attacker-favorable ratio, then sells PTM back for USDT and repays the flash loan, netting ~552 USDT.
**Insight:** On token contracts, look for externally callable functions that move the contract's own token/quote balances (addLiquidity, sync, skim-style helpers) with no access control; combined with a flash loan to set the price ratio, they become a direct drain of protocol-owned liquidity.
