57506 sc high force repay don t update cumulativeearmarked variable
Submitted on Oct 26th 2025 at 20:09:20 UTC by @OxPhantom for Audit Comp | Alchemix V3
Report ID: #57506
Report Type: Smart Contract
Report severity: High
Target: https://github.com/alchemix-finance/v3-poc/blob/immunefi_audit/src/AlchemistV3.sol
Impacts:
Permanent freezing of funds
Description
Brief/Intro
Force repay during liquidation decrements an account’s earmarked debt but does not decrement the global cumulativeEarmarked. This desynchronizes global earmark accounting, leading to an underestimated unearmarked bucket and potentially throttling future earmarks and mis-weighting decay.
Vulnerability Details
In repay(), the contract removes earmark at both the account and global levels:
// Repay debt from earmarked amount of debt first
uint256 earmarkToRemove = credit > account.earmarked ? account.earmarked : credit;
account.earmarked -= earmarkToRemove;
uint256 earmarkPaidGlobal = cumulativeEarmarked > earmarkToRemove ? earmarkToRemove : cumulativeEarmarked;
cumulativeEarmarked -= earmarkPaidGlobal;But in _forceRepay() (used by liquidation pre-step), only the account’s earmark is decremented; the global cumulativeEarmarked is not updated:
Effects:
cumulativeEarmarkedstays too high, soliveUnearmarked = totalDebt - cumulativeEarmarkedis too low.Future
_earmark()calls may clampamountunnecessarily:if (amount > liveUnearmarked) amount = liveUnearmarked;.Earmark/redemption weights and survival math use
cumulativeEarmarked(e.g., in_doLiquidationand decay weighting), potentially skewing per-user attribution after force-repay events.
Impact Details
Operationally reduces earmark throughput post-liquidation (less debt considered unearmarked than reality), delaying redemptions.
Skews global decay/weight accounting (e.g.,
_redemptionWeightis parameterized bycumulativeEarmarked).
References
https://github.com/alchemix-finance/v3-poc/blob/a192ab313c81ba3ab621d9ca1ee000110fbdd1e9/src/AlchemistV3.sol#L758-L763
Proof of Concept
Proof of Concept
You can copy paste this code in AlchemistV3.t.sol and run forge test --mt testLiquidate_POC -vv
This POC demonstrated that the cumulativeEarmarked is not changed by force repay.
Was this helpful?