# Adversary can abuse a quirk of compound redemption to manipulate the underlying exchange rate and maliciously disable cToken collaterals

Compound cToken redeemAmountIn rounds cTokens burned in user's favor, letting an attacker nudge the exchange rate down and trip Reserve's collateral-disable check.

- Payout: Contest reward
- Severity: high
- Program: Reserve
- Credited: 0x52
- Disclosed: 2023-04-27
- Write-up quality: 8/10
- Original: https://github.com/code-423n4/2023-01-reserve-findings/issues/310
- Library page: https://bugbountylibrary.com/r/c4%3A2023-01-reserve%3AH-01
- Tags: domain:web3 impact:dos impact:funds-loss kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:oracle-manipulation vuln:precision-loss

**Target:** CTokenFiatCollateral/CTokenNonFiatCollateral refresh price check over Compound cTokens
**Root cause:** FiatCollateral disables collateral whenever referencePrice < prevReferencePrice, assuming cToken exchange rate never decreases. Compound's redeem-by-amount path truncates redeemTokens in the user's favor, so a redemption can lower netAssets/totalSupply slightly.
**Steps:**
1. Note exchangeRate = (totalCash+totalBorrows-totalReserves)*1e18/totalSupply.
2. Call `redeem(redeemAmountIn)` with a tiny redeemAmountIn so `redeemTokens = div_(redeemAmountIn, exchangeRate)` truncates to 1 token burned for more underlying than implied.
3. Recompute rate: e.g. 300k ETH/15M cETH, redeem 99e8 wei -> burn 1 cToken -> rate drops to 199999999999999933333333333.
4. Call `refresh()` on the cToken collateral to store the current (pre-manipulation) rate.
5. Perform the redemption to lower the rate.
6. Call `refresh()` again; truncated 18dp referencePrice < prevReferencePrice triggers `markStatus(CollateralStatus.DISABLED)`.
7. Protocol must liquidate holdings into backup asset, incurring loss.
**How found:** Code review of FiatCollateral's `referencePrice < prevReferencePrice` disable logic against the assumption that cToken exchange rates are monotonic; traced into Compound CToken.sol redeem path and spotted the `div_` rounding in favor of the user, then modeled the rate formula to confirm a dust redemption lowers the ratio.
**Exploitation:** Attacker refreshes collateral to snapshot rate, executes a dust redemption via Compound redeemAmountIn to shave the exchange rate, then refreshes again to force DISABLED status, forcing the rToken vault to liquidate cToken holdings into a backup asset at a loss. Repeatable with consecutive redemptions to lower rate further.
**Escalation:** Consecutive redemptions can push the rate arbitrarily lower, making disablement reliable regardless of interest accrued.
**Insight:** When a protocol treats an external exchange rate as monotonically non-decreasing, check the external contract's rounding direction on redeem/mint-by-amount paths: truncation in the user's favor can shave the ratio by a wei, enough to trip strict `<` comparisons.
