58275 sc high account rawlocked not clear even when debt is clear
Submitted on Oct 31st 2025 at 22:10:41 UTC by @emmac002 for Audit Comp | Alchemix V3
Report ID: #58275
Report Type: Smart Contract
Report severity: High
Target: https://github.com/alchemix-finance/v3-poc/blob/immunefi_audit/src/AlchemistV3.sol
Impacts:
Users lose funds
Description
Brief/Intro
A bug in the _subDebt function causes borrower rawLocked not clear even after full debt repayment (account.debt == 0) when minimumCollateralization/convertDebtTokensToYield is increased post-borrow. This occurs because _subDebt caps the toFree amount at _totalLocked but still computes lockedCollateral using the new higher ratio, leaving a residual in account.rawLocked.
Vulnerability Details
The vulnerability lies in the _subDebt function, which is called to reduce a position’s debt. The function correctly caps the amount of collateral to free (toFree) at the total locked amount (_totalLocked), but fails to adjust account.rawLocked when the required locked collateral exceeds _totalLocked due to a higher minimumCollateralizatio/convertDebtTokensToYield.
function _addDebt(uint256 tokenId, uint256 amount) internal {
Account storage account = _accounts[tokenId];
// Update collateral variables
uint256 toLock = convertDebtTokensToYield(amount) * minimumCollateralization / FIXED_POINT_SCALAR;
uint256 lockedCollateral = convertDebtTokensToYield(account.debt) * minimumCollateralization / FIXED_POINT_SCALAR;
if (account.collateralBalance - lockedCollateral < toLock) revert Undercollateralized();
account.rawLocked = lockedCollateral + toLock;
_totalLocked += toLock;
account.debt += amount;
totalDebt += amount;
}User addDebt(100) and the minimumCollateralization = 1.5, toLock = 100 * 1.5 = 150, lockedCollateral = 0, account.rawLocked = 150, _totalLocked = 150, totalDebt = 100, account.debt = 100
Admin increases minimumCollateralization or convertDebtTokensToYield increases, User subDebt(100) and the minimumCollateralization = 2, toFree = 100 * 2 = 200, lockedCollateral = 100 * 2 = 200, toFree (200) > _totalLocked (150), so toFree = 150, account.rawLocked = 200 - 150 = 50, account.debt = 100 - 100 = 0
If in the _sync function _collateralWeight is not 0, then collateralToRemove will be incorrectly deducted from account.collateralBalance, even when the user has cleared the debt.
Impact Details
Any borrower may lose funds if account.rawLocked is not properly cleared
Solution
References
(https://github.com/alchemix-finance/v3-poc/blob/immunefi_audit/src/AlchemistV3.sol?utm_source=immunefi#L936-L947)
Proof of Concept
Proof of Concept
Test:
Output:
Was this helpful?