58518 sc critical liquidation will steal repayment fee from innocent users funds
Submitted on Nov 2nd 2025 at 23:47:30 UTC by @gizzy for Audit Comp | Alchemix V3
Report ID: #58518
Report Type: Smart Contract
Report severity: Critical
Target: https://github.com/alchemix-finance/v3-poc/blob/immunefi_audit/src/AlchemistV3.sol
Impacts:
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(uint256 accountId, uint256 repaidAmountInYield) internal returns (uint256 fee) {
Account storage account = _accounts[accountId];
// calculate repayment fee and deduct from account
fee = repaidAmountInYield * repaymentFee / BPS;
account.collateralBalance -= fee > account.collateralBalance ? account.collateralBalance : fee;
emit RepaymentFee(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 accountLine 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:
Location 1: _liquidate() line 833:
Location 2: _liquidate() line 847:
Step-by-Step Attack Vector
Initial Setup
Alice: Deposits 1,000 MYT shares worth $1,000, borrows $900 (max LTV)
Bob: Deposits 1,000 MYT shares worth $1,000, borrows nothing (provides liquidity)
Total Alchemist Balance: 2,000 MYT shares
Attack Execution
Step 1: Alice Creates Redemption
Alice creates redemption in Transmuter with all 900 alTokens
Time passes: Full transmutation period
Earmarked debt: ~$899
Step 2: Price Crash
MYT price drops 10%
Alice's collateral value: 1,000 shares × $0.909 = $909
Alice's debt: $900
Collateralization: 101% (below 105% threshold)
Step 3: Liquidation
Liquidator calls liquidate(aliceTokenId):
Bob Tries to Withdraw
When Bob tries to withdraw his full 1,000 shares:
Bob is now DOS'd from his own funds or will receive less than his deposited amount.
Impact
Direct Theft of User Funds
Innocent users lose funds to cover fees from insolvent accounts
DOS
When multiple users with insufficient collateral are liquidated, the theft compounds
Eventually, the Alchemist contract becomes insolvent (
_mytSharesDeposited > actual balance)
Likelihood
High - This occurs whenever:
A liquidated account has insufficient collateral to cover the full 3% repayment fee
Reference
https://github.com/alchemix-finance/v3-poc/blob/a192ab313c81ba3ab621d9ca1ee000110fbdd1e9/src/AlchemistV3.sol#L900C3-L907C6
Proof of Concept
Proof of Concept
Add this test to src/test/AlchemistV3.t.sol (https://github.com/alchemix-finance/v3-poc/blob/immunefi_audit/src/test/AlchemistV3.t.sol):
Running the POC
Was this helpful?