58101 sc critical repayment only liquidation overpays fee from pooled collateral

Submitted on Oct 30th 2025 at 17:00:37 UTC by @Anirruth for Audit Comp | Alchemix V3arrow-up-right

  • Report ID: #58101

  • Report Type: Smart Contract

  • Report severity: Critical

  • Target: https://github.com/alchemix-finance/v3-poc/blob/immunefi_audit/src/AlchemistV3.sol

  • Impacts:

    • Theft of unclaimed yield

Description

Brief/Intro

When liquidation enters the “repayment-only” path (earmarks fully repay the borrower’s debt), the protocol pays the liquidator the full theoretical repayment fee even if the borrower’s collateral couldn’t fund it. The shortfall is taken from the contract’s MYT balance.

Vulnerability Details

  • Liquidation first earmarks and repays via _forceRepay. If this fully clears debt, it executes the following if block: https://github.com/alchemix-finance/v3-poc/blob/immunefi_audit/src/AlchemistV3.sol?utm_source=immunefi#L823-L828

// If debt is fully cleared, return with only the repaid amount, no liquidation needed, caller receives repayment fee
        if (account.debt == 0) {
            feeInYield = _resolveRepaymentFee(accountId, repaidAmountInYield);
            TokenUtils.safeTransfer(myt, msg.sender, feeInYield);
            return (repaidAmountInYield, feeInYield, 0);
        }
  • The _resolveRepaymentFee computes the theoretical fee and deducts only what’s available from the borrower’s balance, but returns the full, unclamped fee: https://github.com/alchemix-finance/v3-poc/blob/immunefi_audit/src/AlchemistV3.sol?utm_source=immunefi#L900-L907

  • The call site then transfers that full theoretical fee to the liquidator from the contract’s balance, regardless of what was actually deducted from the borrower.

The calculation in the _doLiquidation function has proper checks,

Consider the following scenario:

  • Debt repaid: 100 MYT; repayment fee: 10% → theoretical fee = 10 MYT.

  • Borrower’s remaining collateral balance: 2 MYT.

  • _resolveRepaymentFee deducts 2 from collateral balance but the function returns returns 10.

  • Liquidator receives 10 where 8 is sourced from the contract pool.

Impact Details

Direct loss of funds from the pooled collateral.

Liquidators can repeatedly extract fee shortfalls from pooled MYT across many underfunded accounts, draining the contract’s balance.

References

https://github.com/alchemix-finance/v3-poc/blob/immunefi_audit/src/AlchemistV3.sol?utm_source=immunefi#L823-L828

https://github.com/alchemix-finance/v3-poc/blob/immunefi_audit/src/AlchemistV3.sol?utm_source=immunefi#L900-L907

Proof of Concept

Proof of Concept

Paste the following test in AlchemistV3.t.sol and run forge test --match-test testRepaymentFee_Overdraw_FromPool_OnRepaymentOnlyPath

Was this helpful?