57335 sc medium zero min out erc 4626 deposits cause under mint and permanent allocation loss

Submitted on Oct 25th 2025 at 10:23:14 UTC by @riptide for Audit Comp | Alchemix V3arrow-up-right

  • Report ID: #57335

  • Report Type: Smart Contract

  • Report severity: Medium

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

  • Impacts:

    • Contract fails to deliver promised returns, but doesn't lose value

Description

Summary

TokeAutoEthStrategy._allocate deposits into an ERC-4626 vault with minSharesOut = 0 and immediately stakes whatever shares are minted, while MYTStrategy.allocate records the full asset amount as allocated without verifying realized shares. This enables front‑running/donation manipulation of the ERC‑4626 price-per-share so the strategy mints far fewer shares than expected, permanently crystallizing loss and breaking allocation accounting. The same pattern appears in other non ERC-4626 adapters.

Finding Description

The base strategy executes the external deposit before final accounting and trusts the adapter’s return value; no per-deposit floor or post-check exists:

// File: src/MYTStrategy.sol
function allocate(bytes memory data, uint256 assets, bytes4 selector, address sender)
    external
    onlyVault
    returns (bytes32[] memory strategyIds, int256 change)
{
    if (killSwitch) { return (ids(), int256(0)); }
    require(assets > 0, "Zero amount");
    uint256 oldAllocation = abi.decode(data, (uint256));
    uint256 amountAllocated = _allocate(assets);  // external action happens here (pre-commit)
    uint256 newAllocation = oldAllocation + amountAllocated;
    emit Allocate(amountAllocated, address(this));
    return (ids(), int256(newAllocation) - int256(oldAllocation));
}

The adapter mints ERC-4626 shares with a literal zero min-out and immediately stakes them, then returns the input asset amount (not minted shares):

The router API expects a caller-supplied minimum, which is ignored:

Allocations are operator-triggered and forwarded unchanged; computed caps are not applied:

The same lack of min-out and post-verification exists in other adapters:

Result: an attacker can donate underlying to the ERC-4626 vault (inflating totalAssets) just before the deposit so convertToShares(amount) under-mints, with the strategy staking the few shares and the vault recording the full amount as allocated.

Test Results: A proof-of-concept test demonstrates the vulnerability with the following parameters:

  • Initial vault state: 100 shares, 100 assets (1:1 ratio)

  • Donation: 900 assets (900% of initial assets)

  • Victim deposit: 10 assets

  • Result: 1 share minted, worth ~9.99 assets (0.01% loss)

  • Conclusion: ERC-4626's proportional pricing mechanism minimizes actual financial impact

Attack Steps

  1. Ensure the ERC-4626 vault (e.g., autoEth) is donation-sensitive and has nonzero totalSupply; optionally pre-hold a large share position for profit capture.

  2. Observe AlchemistAllocator.allocate(adapter = TokeAutoEthStrategy, amount = A) in mempool; transaction will call MYTStrategy.allocate then TokeAutoEthStrategy._allocate(A).

  3. Front-run with WETH.transfer(autoEth, D) to inflate totalAssets; no shares minted.

  4. Victim executes router.depositMax(autoEth, TokeAutoEthStrategy, 0); autoEth.deposit(A) mints sV = convertToShares(A) with inflated denominator; strategy calls rewarder.stake(..., sV).

  5. MYTStrategy.allocate returns amountAllocated = A; vault sets newAllocation = oldAllocation + A, persisting mismatch (few shares backing full allocation).

  6. Back-run with autoEth.redeem(attackerShares, attacker, attacker) to withdraw underlying at improved PPS; profit approaches the victim’s deposit when attacker pre-holds most shares; otherwise the attack is a griefing loss for the protocol.

Likelihood (low)

Exploitation requires an ERC-4626 that counts raw donations in totalAssets, a mempool-visible allocation call, and precise front-running. Profitability demands attacker pre-hold a substantial share fraction; otherwise, large, unrecoverable donations are needed to materially depress minted shares (e.g., ~101 ETH donation for 1% on 10k ETH TVL: D ≈ r/(1−r) × TVL).

While the technical conditions for exploitation exist (ERC-4626 donation sensitivity, mempool visibility, front-running), the impact is minimal (~0.01% loss). Attackers would need to invest significant capital in donations and MEV infrastructure for negligible returns, making this attack economically unviable in practice.

Impact (medium)

ERC-4626 donation attacks have minimal impact (~0.01% loss) due to the standard's proportional pricing mechanism. While the vulnerability exists (strategies return input amount instead of realized shares), the ERC-4626 convertToAssets() function compensates for inflated totalAssets by proportionally increasing share values.

Contract fails to deliver promised returns, but doesn't lose value Vault records full allocation but strategy holds fewer shares leading to accounting inconsistency between recorded allocation and actual shares held.

Mitigation

Given the minimal impact, consider implementing proper accounting by having strategies return vault.convertToAssets(mintedShares) instead of the input amount, which would eliminate the accounting mismatch without requiring complex slippage protection.

Proof of Concept

Proof of Concept

Add to test/MYTStrategy.t.sol

Needed custom contracts for the test

Was this helpful?