# Solvency tick divergence blind spot in RiskEngine.getSolvencyTicks

RiskEngine.getSolvencyTicks' squared-norm gate is bypassed by symmetric tick divergence, letting insolvent positions pass single-tick solvency checks.

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

**Target:** RiskEngine.getSolvencyTicks solvency tick selection (Solidity contract)
**Root cause:** The gate sums squared distances from the median tick, so symmetric offsets on opposite sides of the median cancel out and stay under MAX_TICKS_DELTA^2 even when |spotTick - currentTick| exceeds MAX_TICKS_DELTA.
**Steps:**
1. Set medianTick=M, latestTick=M, spotTick=M+0.70*D, currentTick=M-0.70*D with D=MAX_TICKS_DELTA=953.
2. Compute gate: (0.70D)^2 + 0 + (-0.70D)^2 = 0.98D^2 < D^2, so gate does not fire.
3. getSolvencyTicks returns only spotTick (M+667); position solvent at spotTick but insolvent at currentTick (M-667) passes.
4. Run `forge test --match-test test_poc_solvencyBlindSpot -vvv` in test/foundry/core/PoC_SolvencyBlindSpot.t.sol.
**How found:** Noticed isSafeMode() checks |currentTick - spotTick| > MAX_TICKS_DELTA but getSolvencyTicks() does not, then constructed symmetric tick values whose squared distances from median cancel to stay under the threshold.
**Exploitation:** Attacker relies on market conditions producing symmetric tick divergence around the median (e.g. spot +667, current -667); the position is only evaluated at spotTick, so an insolvent directional portfolio passes the solvency check.
**Insight:** When a gate uses an aggregate norm (sum of squared distances from a center), check for symmetric inputs that cancel; compare against sibling functions like isSafeMode that use pairwise divergence checks and look for inconsistent thresholds.
