In AlchemistV3.sol, the _forceRepay and _doLiquidation transfer MYT shares out of the contract (to the transmuter, liquidator, or protocol fee vault) but never decrement _mytSharesDeposited. Consequently, the internal ledger continues to assume those shares are still held. This drifts collateral accounting—global collateralization metrics are overstated, so liquidations can under-react—and deposit-cap enforcement rejects new deposits even after MYT has actually left the vault.
Vulnerability Details
Within _forceRepay and _doLiquidation, the contract transfers MYT shares to external recipients(typically the transmuter, liquidator, or protocol fee vault), but _mytSharesDeposited is never reduced by the amount that actually left the contract. Subsequent logic such as _getTotalUnderlyingValue(), calculateLiquidation, and depositCap checks rely on _mytSharesDeposited as the canonical measure of MYT held by AlchemistV3.
Because the counter is not updated after these transfers, every invocation of _forceRepay or _doLiquidation causes the internal ledger to drift further from the real balance. This bug triggers on every liquidation or forced repayment, independent of the caller, so it is both easy to reach and repeatedly exploitable.
Impact Details
Collateral accounting drift – Global metrics (e.g., collateralization ratios) are overstated, enabling inaccurate positions to avoid or delay liquidation, thereby increasing insolvency risk.
DepositCap blockage – The contract continues to believe the cap is saturated even after MYT shares have been removed, so new deposits are rejected, blocking legitimate users and impairing protocol operations.
Recommendation
In both _forceRepay and _doLiquidation, subtract the exact MYT amount that leaves the contract (principal and any fees) from _mytSharesDeposited, so the internal ledger stays aligned with the actual balance.