56402 sc high killswitch leaves vault assets stranded and blocks withdrawals

Submitted on Oct 15th 2025 at 16:10:23 UTC by @spongebob for Audit Comp | Alchemix V3arrow-up-right

  • Report ID: #56402

  • Report Type: Smart Contract

  • Report severity: High

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

  • Impacts:

    • Permanent freezing of funds

    • Protocol insolvency

Description

https://github.com/alchemix-finance/v3-poc/blob/a192ab313c81ba3ab621d9ca1ee000110fbdd1e9/src/MYTStrategy.sol#L107 short-circuits allocate by returning (ids(), 0) when killSwitch is true.

However, the vault has already pushed the requested assets into the adapter before that return executes.

https://github.com/alchemix-finance/v3-poc/blob/a192ab313c81ba3ab621d9ca1ee000110fbdd1e9/lib/vault-v2/src/VaultV2.sol#L574

Because the adapter never reverts, those tokens stay parked on the strategy contract while the vault’s caps/allocation stay unchanged (change = 0) and realAssets implementations such as EulerUSDCStrategy.realAssets() ignore that idle balance, so the vault under-reports its assets and solvency.

The same silent bypass exists in deallocate.

https://github.com/alchemix-finance/v3-poc/blob/a192ab313c81ba3ab621d9ca1ee000110fbdd1e9/src/MYTStrategy.sol#L124

The vault still calls SafeERC20Lib.safeTransferFrom for the full assets amount (lib/vault-v2/src/VaultV2.sol:610), but the strategy never unwinds or approves funds, so the call either reverts blocking withdrawals when this adapter is the only liquidity path, or pulls idle tokens that were previously stranded, again leaving allocation bookkeeping untouched.

No explicit signal is emitted when the kill switch bypass triggers, so operations/incident response can’t distinguish between genuine success and a skipped execution, matching the incident-response gap you described.

Impact

This bug has two impacts

  1. Permanent freezing of funds: Once killSwitch is true, the vault’s deallocate (and forceDeallocate) calls always revert because the strategy short-circuits before unwinding and approving assets. Any liquidity held in that adapter becomes irretrievable through the supported paths, so user withdrawals can be blocked indefinitely while the switch remains on.

  2. Protocol insolvency: During allocation, the vault still transfers the requested assets into the adapter before the kill-switch bypass. Because the adapter reports zero change, the vault stops accounting for those funds even though they now sit idle on the strategy (and most realAssets() implementations ignore that idle balance). The vault’s recorded total assets shrink while liabilities stay constant, enabling share-price distortions that can be exploited when solvency is restored.

Recommendation

  • Make the adapter revert with a dedicated KillSwitchActive error (or perform a best-effort unwind before reverting) instead of returning zero so the vault can deterministically roll over to alternate routes. Reverting also undoes the pre-call safeTransfer.

  • Emit a KillSwitchBypass event (include direction and assets) whenever an emergency path triggers, so on-call teams can reconcile stuck balances quickly.

Proof of Concept

Add this test to MYTStrategy.t.sol and run forge test --mt testPOC_KillSwitch_Freezes_Funds_And_Causes_Insolvency -vvvv

Was this helpful?