58143 sc low unused cap enforcement variables adjusted
Submitted on Oct 30th 2025 at 22:58:51 UTC by @w3llyc4de20Ik2nn1 for Audit Comp | Alchemix V3
Report ID: #58143
Report Type: Smart Contract
Report severity: Low
Target: https://github.com/alchemix-finance/v3-poc/blob/immunefi_audit/src/AlchemistAllocator.sol
Impacts:
Protocol insolvency
Description
Brief/Intro
The AlchemistAllocator calculates an adjusted cap by selecting the appropriate limit between absoluteCap, relativeCap, and daoTarget but fails to enforce it, allowing allocate and deallocate calls to bypass intended risk limits and pass unchecked amounts to the vault.
Vulnerability Details
Offer a detailed explanation of the vulnerability This issue affects both allocate and deallocate functions. Here's the full relevant code for each, highlighting the unused adjusted calculation: In the AlchemistAllocator.sol,
In allocate function:
function allocate(address adapter, uint256 amount) external {
require(msg.sender == admin || operators[msg.sender], "PD");
bytes32 id = IMYTStrategy(adapter).adapterId();
uint256 absoluteCap = vault.absoluteCap(id);
uint256 relativeCap = vault.relativeCap(id);
// FIXME get this from the StrategyClassificationProxy for the respective risk class
uint256 daoTarget = type(uint256).max;
uint256 adjusted = absoluteCap > relativeCap ? absoluteCap : relativeCap;
if (msg.sender != admin) {
// caller is operator
adjusted = adjusted > daoTarget ? adjusted : daoTarget;
}
// pass the old allocation to the adapter
bytes memory oldAllocation = abi.encode(vault.allocation(id));
vault.allocate(adapter, oldAllocation, amount);
} In deallocate function:
The variables absoluteCap, relativeCap, and daoTarget are fetched to compute adjusted, which is meant to represent a safe limit for the amount being allocated or deallocated based on strategy caps and targets; however, adjusted is calculated but never used or compared against amount, so the vault receives the full amount without any limit enforcement.
Impact Details
Without enforcing adjusted against amount, the contract allows unlimited allocations or deallocations, bypassing risk limits and potentially exposing the vault to excessive funds in unsafe strategies.
Recommended Fix
Add a check like require(amount <= adjusted, "Exceeds cap"); in allocate.
For deallocate, check require(amount <= vault.allocation(id), "Exceeds current allocation");
References
https://github.com/alchemix-finance/v3-poc/blob/immunefi_audit/src/AlchemistAllocator.sol?utm_source=immunefi
Proof of Concept
Proof of Concept
The Bug is Crystal Clear:
Allocator fetches absoluteCap = 200 ether
Allocator fetches relativeCap = 0.10e18 (= 50 ether in assets)
Allocator calculates internally: adjusted = max(200, 50) = 200 ether
Allocator NEVER checks if amount (100e) <= adjusted (200e)
Allocator immediately calls vault.allocate(100 ether)
Vault enforces its own relativeCap and reverts with RelativeCapExceeded()
Why This Proves the Vulnerability:
The allocator's logic determined that absoluteCap (200e) should be the governing limit, NOT relativeCap (50e). This is what the adjusted calculation represents - picking the maximum of the two caps.
If the allocator had enforced its adjusted calculation:
It would check: require(100 <= 200) PASS
The allocation would be allowed from the allocator's perspective
But since the allocator ignores adjusted:
It blindly passes 100 ether to the vault
The vault independently enforces BOTH caps (not just the max)
The vault rejects because 100 > 50 (relative cap)
This makes the entire cap selection logic dead code with no purpose, proving the bug report is valid and definitively proves the unused adjusted variable vulnerability!
Was this helpful?