Direct theft of any user funds, whether at-rest or in-motion, other than unclaimed yield
Description
Summary
The _resolveRepaymentFee() function in AlchemistV3.sol has a critical accounting bug where it returns the calculated fee amount instead of the actual amount deducted from the user's collateral. When a liquidated account has insufficient collateral to cover the full repayment fee, the function caps the deduction to the available balance but still returns the uncapped fee. This causes the protocol to transfer more MYT shares than it actually deducted from the account, stealing funds directly from other users' collateral.
Vulnerability Details
Root Cause
In AlchemistV3.sol:909-916, the _resolveRepaymentFee() function:
function_resolveRepaymentFee(uint256accountId,uint256repaidAmountInYield)internalreturns(uint256fee){ Account storage account = _accounts[accountId];// calculate repayment fee and deduct from account fee = repaidAmountInYield * repaymentFee / BPS; account.collateralBalance -= fee > account.collateralBalance ? account.collateralBalance : fee;emitRepaymentFee(accountId, repaidAmountInYield,msg.sender, fee);return fee;// ← BUG: Returns calculated fee, not actual deduction}
The Bug:
Line 912: Calculates fee = repaidAmount × 3%
Line 913: Deducts min(fee, account.collateralBalance) from the account
Line 915: Returns the original fee, not the capped amount
The returned fee is sent to the liquidator via TokenUtils.safeTransfer(myt, msg.sender, feeInYield) in two places: