# Intra-epoch rateAtTarget updates in CollateralTracker._updateInterestRate() allow compounding interest rate errors

CollateralTracker._updateInterestRate updates rateAtTarget every call even within the same 4-second epoch, letting repeated calls compound borrowIndex errors and misprice debt.

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

**Target:** CollateralTracker interest accrual / RiskEngine IRM
**Root cause:** rateAtTarget is updated on every _accrueInterest call while marketEpoch only advances when deltaTime>0, so intra-epoch calls apply non-zero elapsed time against a stale epoch reference and compound.
**Steps:**
1. Call CollateralTracker._accrueInterest() multiple times within the same 4s epoch (block.timestamp>>2 unchanged).
2. Observe _updateInterestRate() writes s_marketState.rateAtTarget via updateRateAtTarget each call.
3. Note RiskEngine._borrowRate() computes elapsed = block.timestamp - (currentEpoch<<2) which is non-zero (e.g. 3s) even though epoch hasn't advanced.
4. Each call starts from the previously manipulated rateAtTarget, compounding borrowIndex.
5. Run `forge test --mt test_audit_accrueInterest_manipulateRateAtTarget_combineAttack -vvv` to see amplified effect using peak utilization in a single tx.
**How found:** Code reading of _accrueInterest/_updateInterestRate vs _calculateCurrentInterestState revealed rateAtTarget updates unconditionally while marketEpoch only advances on deltaTime>0; foundry cast confirmed non-zero elapsed within an epoch.
**Exploitation:** Attacker triggers repeated _accrueInterest calls within a 4-second window (or a single tx using peak utilization) to compound rateAtTarget updates, skewing borrowIndex and thus user debt/solvency calculations.
**Escalation:** Combining with peak utilization in a single transaction amplifies the otherwise small sub-4s elapsed-time error.
**Insight:** When a protocol batches time into epochs, check that every state variable derived from elapsed time is gated by the same epoch-advance condition; mismatched gating lets intra-epoch calls compound.
