# StabilizerNode.stabilize uses stale GlobalImpliedCollateralService data, which will make stabilize incorrect

StabilizerNode.stabilize reads stale GlobalImpliedCollateralService.collateralRatio before syncing, so after delegateCapital drains collateral the stabilize price target is computed from inflated collateral data.

- Payout: Contest reward
- Severity: high
- Program: Malt Protocol
- Credited: cccz
- Disclosed: 2023-05-01
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2023-02-malt-findings/issues/9
- Library page: https://bugbountylibrary.com/r/c4%3A2023-02-malt%3AH-06
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:solidity technique:chained technique:source-review vuln:accounting-error vuln:oracle-manipulation

**Target:** StabilizerNode / ImpliedCollateralService (Solidity contracts)
**Root cause:** syncGlobalCollateral() is only called at the end of stabilize(), so getActualPriceTarget/getSwingTraderEntryPrice consume a stale collateralRatio that no longer reflects collateral moved out via SwingTraderManager.delegateCapital.
**Steps:**
1. Call impliedCollateralService.syncGlobalCollateral() to snapshot current collateral.
2. Call SwingTraderManager.delegateCapital(amount, destination) to transfer collateralToken out, leaving globalIC.collateralRatio() higher than actual.
3. Call StabilizerNode.stabilize(); it reads maltDataLab.getActualPriceTarget()/getSwingTraderEntryPrice() which use the stale globalIC.collateralRatio().
4. Observe stabilize computes wrong price target/entry price; syncGlobalCollateral only runs at function end.
**How found:** Code reading of stabilize() ordering: noticed syncGlobalCollateral() only at function end while getActualPriceTarget depends on globalIC.collateralRatio(), then traced delegateCapital as a state change that desyncs the ratio.
**Exploitation:** Attacker (or any capital-delegate role holder) moves collateral out via delegateCapital between syncs, then triggers stabilize so supply adjustment uses an inflated collateralRatio, pushing malt off peg.
**Insight:** When a view-based oracle/ratio feeds a state-changing core function, check whether the cache is refreshed before reads, not after; any privileged transfer that changes balances between syncs creates a stale-read window.
