58413 sc critical attacker user can prevent earmark from updating the earnmarkweight causing the transmuter action to repay det gradually to fail for all users

Submitted on Nov 2nd 2025 at 04:51:59 UTC by @damdam0249 for Audit Comp | Alchemix V3arrow-up-right

  • Report ID: #58413

  • Report Type: Smart Contract

  • Report severity: Critical

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

  • Impacts:

    • Temporary freezing of funds for at least 24 hour

Description

Brief/Intro

Users who lock their debt tokens in the transmuter will have their debt repaid gradually based on the time taken to transmute. However, there is an issue with the query function in the transmuter, which incorrectly returns 0 when both the start and end blocks are the same we set to zero. This means in a constant update or "poke" within the same block number, 0 debt are earmark. Consequently, this causes the entire transmuter repayment system to fail, and users end up spending more funds to clear this debt than they would have otherwise. This situation highlights the risk of freezing the earmark or debt repayment model in the transmuter, ultimately forcing users to repay with MYT or face liquidation.

Vulnerability Details

   
/// @inheritdoc ITransmuter
    function queryGraph(uint256 startBlock, uint256 endBlock) external view returns (uint256) {

@here bug        if (endBlock <= startBlock) return 0;

        int256 queried = _stakingGraph.queryStake(startBlock, endBlock);
        if (queried == 0) return 0;

        // You currently add +1 for rounding; keep in mind this can create off-by-one deltas.
        return (queried / BLOCK_SCALING_FACTOR).toUint256()
            + (queried % BLOCK_SCALING_FACTOR == 0 ? 0 : 1);
    }

The earmark function calls query and set and check lastsaved earmarked = 1 against block.number. If poke is done within this time frame, the attacker/user will successfully keep the system stagnant preventing the earmarked process from proceed as it should.

This is a huge problem during the redeem call as the system will not update the entire system correctly forcing total debt to be greater than total synthetic asset also this affects the collateral weight which is used with the rawlocked this causes the entire system values to be incorrect

Impact Details

The main consequence is that the transmuter’s earmark process can get stuck, freezing redemptions and throwing the global debt and collateral accounting out of sync. This creates several issues:

Debt and Collateral Mismatch: The total debt stays higher than the total supply of synthetic assets, breaking key system assumptions.

Higher Repayment Costs: Users may need to repay more debt than expected or use extra MYT to clear their positions.

Incorrect Collateral Tracking: Locked collateral values (like rawLocked and _totalLocked) become inconsistent with the actual debt, which can trigger underflows or inaccurate collateral weight calculations.

System-Wide Failure Risk: Continuous zero-return earmarks can effectively block redemptions and liquidations, leading to a persistent denial-of-service across the system.

References

Proof of Concept

Proof of Concept

RESULT

Total synthetic debt is 0 Total debt > 0 And users pay more than the should the log of 1 is the present code

2 RESULT of how the system should work and user's expected balance ideally

Was this helpful?