58112 sc high a malicious user can avoid getting penalized upon a transmuter redemption by depositing and withdrawing collateral in the alchemist

Submitted on Oct 30th 2025 at 18:14:31 UTC by @Oxdeadmanwalking for Audit Comp | Alchemix V3arrow-up-right

  • Report ID: #58112

  • Report Type: Smart Contract

  • Report severity: High

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

  • Impacts:

    • Smart contract unable to operate due to lack of token funds

Description

Brief/Intro

The Transmuter, calculates the badDebtRatio as totalSyntheticsIssued (debt) /totalValue (collateral in alchemist and transmuter which is then used to scale down the redeemed amount in case of bad debt to retain the health of the protocol. In order to calculate the totalValue the transmuter queries alchemist.getTotalUnderlyingValue(). getTotalUnderlyingValue however can easily be manipulatable via collateral deposits which can later be withdrawn with no cost, enabling the user to avoid the badDebtRatio penalty entirely. Since bad debt represents a deficit in assets (collateral) relative to debt and debt is represented as alAssets which can then be redeemed in the transmuter for underlying, avoiding the penalty means that later redemptions will be unable to be serviced. As a result, later users will lose their funds as underlying shares will have been depleted in the transmuter by the manipulation and earmarks will be unable to cover them.

Vulnerability Details

In Transmuter, badDebtRatio is calculated as follows:

        // If the system experiences bad debt we use this ratio to scale back the value of yield tokens that are transmuted
        uint256 yieldTokenBalance = TokenUtils.safeBalanceOf(alchemist.myt(), address(this));
        // Avoid divide by 0
        uint256 denominator = alchemist.getTotalUnderlyingValue() + alchemist.convertYieldTokensToUnderlying(yieldTokenBalance) > 0 ? alchemist.getTotalUnderlyingValue() + alchemist.convertYieldTokensToUnderlying(yieldTokenBalance) : 1;
        
        uint256 badDebtRatio = alchemist.totalSyntheticsIssued() * 10**TokenUtils.expectDecimals(alchemist.underlyingToken()) / denominator;

        if (badDebtRatio > 1e18) {
        // penalty applied here
            scaledTransmuted = amountTransmuted * FIXED_POINT_SCALAR / badDebtRatio;
        }

The numerator includes alchemist.getTotalUnderlyingValue() which in turn return the total underlying collateral deposited in the alchemist.

_mytSharesDeposited however, gets increased during a deposit, even if the depositor does not borrow any assets.

This opens a manipulation opportunity where someone can

  1. Initiate a redemption and wait for maturity

  2. In the meantime, bad debt occurs, the position matures

  3. The user deposits significant collateral using deposit from another account without borrowing, causing _mytSharesDeposited to be artificially increased

  4. Calls claimRedemption with the inflated _mytSharesDeposited. This queries the achemist to calculate the badDebtRatio but due to the big deposit, the ratio will be significantly less than expected.

  5. The user gets back his whole redeemed amount without scaling it down, avoiding the penalty entirely.

  6. The user then withdraws the deposited collateral from step 3. Note that depositing and withdrawing along with obtaining collateral incurs no cost or fees.

There is also nothing preventing the attacker from performing steps 3 to 6 attomically using a flash loans as 1. The MYT uses underlying collateral such as USDC and ETH which are readily available to flash loan in many venues without cost (like morpho) so a large amount of MYT shares can be obtained easily. 2. deposits and withdrawals from the alchemist can happen in the same block without restrictions. This allows the attacker to bypass the badDebtRatio penalty entirely without any capital.

badDebtRatio scales down the amount returned to the user from the transmuter but burns the whole staked alAssets after maturity. This would mean that the ratio will decrease over time as the numerator will decrease (debt, synthetics) more than the denominator (value).

If the user's redemption from manipulation represents a large share of total redemptions, badDebtRatio will never decrease meaning there wont be enough underlying collateral in the system to process later redemptions since debt will be more than collateral. In this case, later users using the transmuter will lose their funds as calls to claimRedemption will not be able to be serviced.

Impact Details

Avoiding the bad debt ratio penalty can lead to stagnant bad debt which will cause later transmuter users to lose their funds as calls to claimRedemption will not be able to be serviced. If bad debt does not decrease, then the system will also remain insolvent.

References

  • https://github.com/alchemix-finance/v3-poc/blob/a192ab313c81ba3ab621d9ca1ee000110fbdd1e9/src/AlchemistV3.sol#L1238

  • https://github.com/alchemix-finance/v3-poc/blob/a192ab313c81ba3ab621d9ca1ee000110fbdd1e9/src/Transmuter.sol#L219

Proof of Concept

Proof of Concept

  1. Add this test at the end of the file at AlchemistV3.t.sol

  1. Run the test:

  1. Observe the logs. The user was able to successfully redeem more underlying assets from the transmuter by performing the deposit. Then, he was able to withdraw the whole amount without any cost.

Was this helpful?