# An attacker can manipulate oracle easily

Permissionless pokeOracle locks a flash-loan-manipulated tick into the oracle for a full 64-second epoch, letting attackers shift prices 149 ticks per epoch cumulatively.

- Payout: Contest reward
- Severity: medium
- Program: Panoptic
- Credited: Tupaia
- Disclosed: 2026-03-09
- Write-up quality: 6/10
- Original: https://code4rena.com/reports/2025-12-panoptic-next-core#m-11
- Library page: https://bugbountylibrary.com/r/c4%3A2025-12-panoptic-next-core%3AM-11
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:business-logic vuln:flash-loan vuln:oracle-manipulation

**Target:** PanopticPool/OraclePack oracle update mechanism
**Root cause:** computeInternalMedian only updates when the current 64-second epoch differs from the recorded epoch, so the first caller in an epoch locks in the tick; pokeOracle is permissionless and reads a flash-loan-manipulable Uniswap tick.
**Steps:**
1. At an epoch boundary, flash-loan and swap the Uniswap pool to move currentTick toward the desired direction.
2. Call `PanopticPool::pokeOracle()`; `getCurrentTick()` returns the manipulated tick, clamped to ±149 ticks by `clampTick`.
3. Oracle pack is written for this epoch; further `computeInternalMedian` calls return unchanged pack since `differentEpoch` is false.
4. Legitimate pokeOracle calls later in the epoch are no-ops, leaving the manipulated value.
5. Repeat each epoch to accumulate up to 149 ticks of drift per epoch.
**How found:** Code reading of OraclePack::computeInternalMedian epoch-gating logic combined with noticing pokeOracle lacks access control and reads a manipulable spot tick.
**Exploitation:** Attacker frontruns legitimate oracle updates at each epoch boundary, uses flash loans to skew the Uniswap tick, and calls pokeOracle to lock the clamped manipulated tick for the whole epoch, cumulatively distorting oracle price used for solvency checks and liquidations.
**Escalation:** Cumulative drift across multiple epochs (149 ticks each) amplifies distortion beyond single-update clamp.
**Insight:** When an oracle update is gated on a coarse time bucket (epoch) rather than elapsed time, the first caller in each bucket controls the value; check whether that first-caller write is permissionless and fed by a manipulable spot price.
