# Two Pyth prices can be used in the same transaction to attack the LP pools

Pyth pull-oracle lets attacker deposit LP shares at one signed price and withdraw at a higher signed price in one tx, siphoning LP value.

- Payout: Contest reward
- Severity: high
- Program: Perpetual
- Credited: Bauer
- Disclosed: 2024-02-19
- Write-up quality: 7/10
- Original: https://github.com/sherlock-audit/2024-02-perpetual-judging/issues/123
- Library page: https://bugbountylibrary.com/r/sherlock%3A2024-02-perpetual%3AH-1
- Tags: domain:web3 impact:funds-loss kind:contest platform:sherlock sev:high tech:solidity technique:source-review vuln:business-logic vuln:flash-loan vuln:oracle-manipulation

**Target:** OracleMaker / SpotHedgeBaseMaker LP deposit-withdraw with PythOracleAdapter
**Root cause:** LP share pricing uses the most recently stored Pyth price with only a maxAge check; two valid signed prices can be submitted in one transaction, so deposit and withdraw can be priced differently.
**Steps:**
1. Obtain two signed Pyth base prices for the same feed, both within maxAge, with price_low < price_high.
2. Deploy attacker contract holding both signed updates.
3. Call `PythOracleAdapter.updatePrice()` with the low price, then `OracleMaker.deposit()` (or SpotHedgeBaseMaker) to mint shares at the low valuation.
4. Call `updatePrice()` again with the high price.
5. Call `withdraw()` to redeem shares at the high valuation, capturing the delta.
6. Optionally wrap in a flash loan to magnify the price-difference profit since deposit/withdraw have no fees.
**How found:** Code review of PythOracleAdapter: noticed pull-oracle model only enforces maxAge, no monotonicity/freshness binding between price updates and deposit/withdraw, and that deposit and withdraw each re-read `_getPrice()` independently within one tx.
**Exploitation:** Attacker contract submits two valid Pyth signed prices in a single tx: deposit at the lower price, update to the higher price, withdraw at the higher price. No fees on deposit/withdraw and flash loans amplify the risk-free spread, extracting value that should accrue to existing LPs.
**Escalation:** Flash loans magnify the spread; repeatable across both OracleMaker and SpotHedgeBaseMaker pools.
**Insight:** For pull-oracle integrations, check whether a single transaction can update the oracle multiple times between state-changing calls; maxAge alone doesn't prevent intra-tx price selection. Also check whether deposit/withdraw share pricing re-reads the oracle separately.
